mongo 2.14.1 → 2.15.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (230) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +4 -1
  4. data/Rakefile +8 -15
  5. data/lib/mongo/auth/aws/conversation.rb +1 -4
  6. data/lib/mongo/auth/base.rb +13 -7
  7. data/lib/mongo/auth/conversation_base.rb +32 -0
  8. data/lib/mongo/auth/cr/conversation.rb +6 -29
  9. data/lib/mongo/auth/gssapi/conversation.rb +4 -15
  10. data/lib/mongo/auth/ldap/conversation.rb +3 -14
  11. data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
  12. data/lib/mongo/auth/scram_conversation_base.rb +7 -34
  13. data/lib/mongo/auth/user/view.rb +16 -9
  14. data/lib/mongo/auth/x509/conversation.rb +4 -25
  15. data/lib/mongo/bulk_write.rb +21 -18
  16. data/lib/mongo/client.rb +82 -6
  17. data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
  18. data/lib/mongo/cluster.rb +19 -2
  19. data/lib/mongo/collection/view/aggregation.rb +1 -1
  20. data/lib/mongo/collection/view/change_stream.rb +1 -1
  21. data/lib/mongo/collection/view/iterable.rb +7 -17
  22. data/lib/mongo/collection/view/map_reduce.rb +2 -2
  23. data/lib/mongo/collection/view/readable.rb +42 -20
  24. data/lib/mongo/collection/view/writable.rb +14 -14
  25. data/lib/mongo/collection.rb +6 -6
  26. data/lib/mongo/cursor.rb +2 -12
  27. data/lib/mongo/database/view.rb +1 -1
  28. data/lib/mongo/database.rb +8 -3
  29. data/lib/mongo/error/bulk_write_error.rb +17 -3
  30. data/lib/mongo/error/internal_driver_error.rb +22 -0
  31. data/lib/mongo/error/operation_failure.rb +21 -2
  32. data/lib/mongo/error/parser.rb +65 -12
  33. data/lib/mongo/error/server_api_conflict.rb +23 -0
  34. data/lib/mongo/error/server_api_not_supported.rb +24 -0
  35. data/lib/mongo/error/unmet_dependency.rb +21 -0
  36. data/lib/mongo/error.rb +9 -1
  37. data/lib/mongo/index/view.rb +21 -11
  38. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
  39. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
  40. data/lib/mongo/monitoring.rb +13 -4
  41. data/lib/mongo/operation/collections_info/command.rb +2 -2
  42. data/lib/mongo/operation/collections_info.rb +18 -1
  43. data/lib/mongo/operation/context.rb +99 -0
  44. data/lib/mongo/operation/indexes.rb +15 -1
  45. data/lib/mongo/operation/insert/command.rb +2 -2
  46. data/lib/mongo/operation/insert/legacy.rb +2 -2
  47. data/lib/mongo/operation/insert/op_msg.rb +2 -2
  48. data/lib/mongo/operation/list_collections/result.rb +4 -1
  49. data/lib/mongo/operation/parallel_scan/command.rb +2 -1
  50. data/lib/mongo/operation/result.rb +2 -0
  51. data/lib/mongo/operation/shared/executable.rb +24 -14
  52. data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
  53. data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
  54. data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
  55. data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
  56. data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
  57. data/lib/mongo/operation/shared/response_handling.rb +23 -23
  58. data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
  59. data/lib/mongo/operation/shared/write.rb +8 -18
  60. data/lib/mongo/operation.rb +2 -2
  61. data/lib/mongo/protocol/compressed.rb +51 -5
  62. data/lib/mongo/protocol/message.rb +20 -2
  63. data/lib/mongo/protocol/msg.rb +38 -13
  64. data/lib/mongo/protocol/query.rb +11 -11
  65. data/lib/mongo/query_cache.rb +30 -0
  66. data/lib/mongo/retryable.rb +1 -1
  67. data/lib/mongo/server/app_metadata.rb +52 -18
  68. data/lib/mongo/server/connection.rb +5 -0
  69. data/lib/mongo/server/connection_base.rb +13 -10
  70. data/lib/mongo/server/connection_pool.rb +6 -2
  71. data/lib/mongo/server/description/features.rb +9 -8
  72. data/lib/mongo/server/description.rb +4 -0
  73. data/lib/mongo/server/monitor/app_metadata.rb +1 -1
  74. data/lib/mongo/server/monitor/connection.rb +9 -10
  75. data/lib/mongo/server/monitor.rb +20 -1
  76. data/lib/mongo/server/pending_connection.rb +24 -6
  77. data/lib/mongo/server/push_monitor.rb +11 -1
  78. data/lib/mongo/server.rb +7 -1
  79. data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
  80. data/lib/mongo/session/session_pool.rb +4 -2
  81. data/lib/mongo/session.rb +2 -2
  82. data/lib/mongo/socket/ssl.rb +8 -0
  83. data/lib/mongo/socket.rb +29 -4
  84. data/lib/mongo/uri/options_mapper.rb +38 -0
  85. data/lib/mongo/utils.rb +15 -0
  86. data/lib/mongo/version.rb +1 -1
  87. data/lib/mongo.rb +23 -0
  88. data/spec/README.md +24 -1
  89. data/spec/integration/auth_spec.rb +25 -15
  90. data/spec/integration/bulk_write_error_message_spec.rb +41 -0
  91. data/spec/integration/change_stream_spec.rb +4 -4
  92. data/spec/integration/command_monitoring_spec.rb +2 -2
  93. data/spec/integration/connection_spec.rb +2 -0
  94. data/spec/integration/docs_examples_spec.rb +8 -1
  95. data/spec/integration/fork_reconnect_spec.rb +4 -1
  96. data/spec/integration/ocsp_verifier_spec.rb +13 -7
  97. data/spec/integration/operation_failure_code_spec.rb +1 -1
  98. data/spec/integration/operation_failure_message_spec.rb +90 -0
  99. data/spec/integration/query_cache_spec.rb +0 -45
  100. data/spec/integration/reconnect_spec.rb +1 -1
  101. data/spec/integration/snappy_compression_spec.rb +25 -0
  102. data/spec/integration/srv_monitoring_spec.rb +1 -1
  103. data/spec/integration/transactions_examples_spec.rb +6 -0
  104. data/spec/integration/zlib_compression_spec.rb +1 -1
  105. data/spec/integration/zstd_compression_spec.rb +26 -0
  106. data/spec/lite_spec_helper.rb +7 -1
  107. data/spec/mongo/address_spec.rb +15 -11
  108. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  109. data/spec/mongo/auth/ldap_spec.rb +5 -1
  110. data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
  111. data/spec/mongo/auth/scram_spec.rb +1 -1
  112. data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
  113. data/spec/mongo/client_construction_spec.rb +207 -33
  114. data/spec/mongo/client_spec.rb +17 -0
  115. data/spec/mongo/cluster_spec.rb +1 -0
  116. data/spec/mongo/collection/view/explainable_spec.rb +1 -1
  117. data/spec/mongo/collection/view/readable_spec.rb +33 -19
  118. data/spec/mongo/collection_crud_spec.rb +4357 -0
  119. data/spec/mongo/collection_ddl_spec.rb +534 -0
  120. data/spec/mongo/collection_spec.rb +5 -4859
  121. data/spec/mongo/database_spec.rb +66 -4
  122. data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
  123. data/spec/mongo/error/parser_spec.rb +37 -6
  124. data/spec/mongo/index/view_spec.rb +4 -0
  125. data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
  126. data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
  127. data/spec/mongo/operation/aggregate_spec.rb +2 -1
  128. data/spec/mongo/operation/collections_info_spec.rb +4 -1
  129. data/spec/mongo/operation/command_spec.rb +6 -3
  130. data/spec/mongo/operation/create_index_spec.rb +6 -3
  131. data/spec/mongo/operation/create_user_spec.rb +6 -3
  132. data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
  133. data/spec/mongo/operation/delete_spec.rb +11 -7
  134. data/spec/mongo/operation/drop_index_spec.rb +6 -2
  135. data/spec/mongo/operation/find/legacy_spec.rb +3 -1
  136. data/spec/mongo/operation/get_more_spec.rb +3 -1
  137. data/spec/mongo/operation/indexes_spec.rb +5 -1
  138. data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
  139. data/spec/mongo/operation/insert_spec.rb +15 -12
  140. data/spec/mongo/operation/map_reduce_spec.rb +5 -2
  141. data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
  142. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  143. data/spec/mongo/operation/remove_user_spec.rb +6 -3
  144. data/spec/mongo/operation/result_spec.rb +1 -1
  145. data/spec/mongo/operation/update/bulk_spec.rb +9 -6
  146. data/spec/mongo/operation/update_spec.rb +10 -7
  147. data/spec/mongo/operation/update_user_spec.rb +4 -1
  148. data/spec/mongo/protocol/compressed_spec.rb +26 -12
  149. data/spec/mongo/query_cache_middleware_spec.rb +55 -0
  150. data/spec/mongo/retryable_spec.rb +3 -2
  151. data/spec/mongo/server/app_metadata_shared.rb +7 -33
  152. data/spec/mongo/server/app_metadata_spec.rb +2 -0
  153. data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
  154. data/spec/mongo/server/connection_pool_spec.rb +1 -1
  155. data/spec/mongo/server/connection_spec.rb +24 -17
  156. data/spec/mongo/server/monitor/connection_spec.rb +17 -7
  157. data/spec/mongo/server/monitor_spec.rb +9 -1
  158. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  159. data/spec/mongo/server_spec.rb +15 -2
  160. data/spec/mongo/socket/ssl_spec.rb +40 -0
  161. data/spec/mongo/socket_spec.rb +2 -2
  162. data/spec/mongo/tls_context_hooks_spec.rb +37 -0
  163. data/spec/runners/connection_string.rb +0 -4
  164. data/spec/runners/crud/requirement.rb +40 -3
  165. data/spec/runners/crud/verifier.rb +8 -0
  166. data/spec/runners/transactions/operation.rb +1 -1
  167. data/spec/runners/transactions/test.rb +1 -0
  168. data/spec/runners/unified/assertions.rb +249 -0
  169. data/spec/runners/unified/change_stream_operations.rb +26 -0
  170. data/spec/runners/unified/crud_operations.rb +199 -0
  171. data/spec/runners/unified/ddl_operations.rb +96 -0
  172. data/spec/runners/unified/entity_map.rb +39 -0
  173. data/spec/runners/unified/error.rb +25 -0
  174. data/spec/runners/unified/event_subscriber.rb +91 -0
  175. data/spec/runners/unified/exceptions.rb +21 -0
  176. data/spec/runners/unified/grid_fs_operations.rb +55 -0
  177. data/spec/runners/unified/support_operations.rb +250 -0
  178. data/spec/runners/unified/test.rb +393 -0
  179. data/spec/runners/unified/test_group.rb +28 -0
  180. data/spec/runners/unified/using_hash.rb +31 -0
  181. data/spec/runners/unified.rb +96 -0
  182. data/spec/shared/lib/mrss/cluster_config.rb +0 -3
  183. data/spec/shared/lib/mrss/docker_runner.rb +0 -3
  184. data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
  185. data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
  186. data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
  187. data/spec/shared/shlib/server.sh +1 -1
  188. data/spec/spec_helper.rb +4 -1
  189. data/spec/spec_tests/crud_unified_spec.rb +10 -0
  190. data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
  191. data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
  192. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
  193. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
  194. data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
  195. data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
  196. data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
  197. data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
  198. data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
  199. data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
  200. data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
  201. data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
  202. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
  203. data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
  204. data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
  205. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
  206. data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
  207. data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
  208. data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
  209. data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
  210. data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
  211. data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
  212. data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
  213. data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
  214. data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
  215. data/spec/spec_tests/unified_spec.rb +15 -0
  216. data/spec/spec_tests/uri_options_spec.rb +16 -0
  217. data/spec/spec_tests/versioned_api_spec.rb +10 -0
  218. data/spec/support/client_registry.rb +4 -8
  219. data/spec/support/client_registry_macros.rb +4 -4
  220. data/spec/support/common_shortcuts.rb +15 -1
  221. data/spec/support/shared/session.rb +2 -2
  222. data/spec/support/spec_config.rb +42 -11
  223. data/spec/support/utils.rb +64 -3
  224. data.tar.gz.sig +0 -0
  225. metadata +1005 -915
  226. metadata.gz.sig +0 -0
  227. data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
  228. data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
  229. data/spec/integration/secondary_reads_spec.rb +0 -102
  230. data/spec/support/cluster_config.rb +0 -207
@@ -16,14 +16,6 @@ describe Mongo::Collection do
16
16
  authorized_client['collection_spec'].drop
17
17
  end
18
18
 
19
- let(:collection_invalid_write_concern) do
20
- authorized_collection.client.with(write: INVALID_WRITE_CONCERN)[authorized_collection.name]
21
- end
22
-
23
- let(:collection_with_validator) do
24
- authorized_client[:validating]
25
- end
26
-
27
19
  describe '#==' do
28
20
 
29
21
  let(:database) do
@@ -682,4860 +674,14 @@ describe Mongo::Collection do
682
674
  end
683
675
  end
684
676
 
685
- describe '#create' do
686
- before do
687
- authorized_client[:specs].drop
688
- end
689
-
690
- let(:database) do
691
- authorized_client.database
692
- end
693
-
694
- context 'when the collection has no options' do
695
-
696
- let(:collection) do
697
- described_class.new(database, :specs)
698
- end
699
-
700
- let!(:response) do
701
- collection.create
702
- end
703
-
704
- it 'executes the command' do
705
- expect(response).to be_successful
706
- end
707
-
708
- it 'creates the collection in the database' do
709
- expect(database.collection_names).to include('specs')
710
- end
711
- end
712
-
713
- context 'when the collection has options' do
714
-
715
- context 'when the collection is capped' do
716
-
717
- shared_examples 'a capped collection command' do
718
-
719
- let!(:response) do
720
- collection.create
721
- end
722
-
723
- let(:options) do
724
- { :capped => true, :size => 1024 }
725
- end
726
-
727
- it 'executes the command' do
728
- expect(response).to be_successful
729
- end
730
-
731
- it 'sets the collection as capped' do
732
- expect(collection).to be_capped
733
- end
734
-
735
- it 'creates the collection in the database' do
736
- expect(database.collection_names).to include('specs')
737
- end
738
- end
739
-
740
- shared_examples 'a validated collection command' do
741
-
742
- let!(:response) do
743
- collection.create
744
- end
745
-
746
- let(:options) do
747
- { :validator => { fieldName: { '$gte' => 1024 } },
748
- :validationLevel => 'strict' }
749
- end
750
-
751
- let(:collection_info) do
752
- database.list_collections.find { |i| i['name'] == 'specs' }
753
- end
754
-
755
- it 'executes the command' do
756
- expect(response).to be_successful
757
- end
758
-
759
- it 'sets the collection with validators' do
760
- expect(collection_info['options']['validator']).to eq({ 'fieldName' => { '$gte' => 1024 } })
761
- end
762
-
763
- it 'creates the collection in the database' do
764
- expect(database.collection_names).to include('specs')
765
- end
766
- end
767
-
768
- context 'when instantiating a collection directly' do
769
-
770
- let(:collection) do
771
- described_class.new(database, :specs, options)
772
- end
773
-
774
- it_behaves_like 'a capped collection command'
775
-
776
- context 'when validators can be set' do
777
- min_server_fcv '3.2'
778
- it_behaves_like 'a validated collection command'
779
- end
780
- end
781
-
782
- context 'when instantiating a collection through the database' do
783
-
784
- let(:collection) do
785
- authorized_client[:specs, options]
786
- end
787
-
788
- it_behaves_like 'a capped collection command'
789
-
790
- context 'when validators can be set' do
791
- min_server_fcv '3.2'
792
- it_behaves_like 'a validated collection command'
793
- end
794
- end
795
- end
796
-
797
- context 'when the collection has a write concern' do
798
-
799
- before do
800
- database[:specs].drop
801
- end
802
-
803
- let(:options) do
804
- {
805
- write: INVALID_WRITE_CONCERN
806
- }
807
- end
808
-
809
- let(:collection) do
810
- described_class.new(database, :specs, options)
811
- end
812
-
813
- context 'when the server supports write concern on the create command' do
814
- min_server_fcv '3.4'
815
- require_topology :replica_set
816
-
817
- it 'applies the write concern' do
818
- expect{
819
- collection.create
820
- }.to raise_exception(Mongo::Error::OperationFailure)
821
- end
822
- end
823
-
824
- context 'when write concern passed in as an option' do
825
- min_server_fcv '3.4'
826
- require_topology :replica_set
827
-
828
- before do
829
- database['collection_spec'].drop
830
- end
831
-
832
- let(:events) do
833
- subscriber.command_started_events('create')
834
- end
835
-
836
- let(:options) do
837
- { write_concern: {w: 1} }
838
- end
839
-
840
- let!(:collection) do
841
- authorized_collection.with(options)
842
- end
843
-
844
- let!(:command) do
845
- Utils.get_command_event(authorized_client, 'create') do |client|
846
- collection.create({ write_concern: {w: 2} })
847
- end.command
848
- end
849
-
850
- it 'applies the write concern passed in as an option' do
851
- expect(events.length).to eq(1)
852
- expect(command[:writeConcern][:w]).to eq(2)
853
- end
854
- end
855
-
856
- context 'when the server does not support write concern on the create command' do
857
- max_server_version '3.2'
858
-
859
- it 'does not apply the write concern' do
860
- expect(collection.create).to be_successful
861
- end
862
- end
863
- end
864
-
865
- context 'when the collection has a collation' do
866
-
867
- shared_examples 'a collection command with a collation option' do
868
-
869
- let(:response) do
870
- collection.create
871
- end
872
-
873
- let(:options) do
874
- { :collation => { locale: 'fr' } }
875
- end
876
-
877
- let(:collection_info) do
878
- database.list_collections.find { |i| i['name'] == 'specs' }
879
- end
880
-
881
- before do
882
- collection.drop
883
- end
884
-
885
- context 'when the server supports collations' do
886
- min_server_fcv '3.4'
887
-
888
- it 'executes the command' do
889
- expect(response).to be_successful
890
- end
891
-
892
- it 'sets the collection with a collation' do
893
- response
894
- expect(collection_info['options']['collation']['locale']).to eq('fr')
895
- end
896
-
897
- it 'creates the collection in the database' do
898
- response
899
- expect(database.collection_names).to include('specs')
900
- end
901
- end
902
-
903
- context 'when the server does not support collations' do
904
- max_server_version '3.2'
905
-
906
- it 'raises an error' do
907
- expect {
908
- response
909
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
910
- end
911
-
912
- context 'when a String key is used' do
913
-
914
- let(:options) do
915
- { 'collation' => { locale: 'fr' } }
916
- end
917
-
918
- it 'raises an exception' do
919
- expect {
920
- response
921
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
922
- end
923
- end
924
- end
925
- end
926
-
927
- context 'when instantiating a collection directly' do
928
-
929
- let(:collection) do
930
- described_class.new(database, :specs, options)
931
- end
932
-
933
- it_behaves_like 'a collection command with a collation option'
934
- end
935
-
936
- context 'when instantiating a collection through the database' do
937
-
938
- let(:collection) do
939
- authorized_client[:specs, options]
940
- end
941
-
942
- it_behaves_like 'a collection command with a collation option'
943
- end
944
- end
945
-
946
- context 'when a session is provided' do
947
-
948
- let(:collection) do
949
- authorized_client[:specs]
950
- end
951
-
952
- let(:operation) do
953
- collection.create(session: session)
954
- end
955
-
956
- let(:session) do
957
- authorized_client.start_session
958
- end
959
-
960
- let(:client) do
961
- authorized_client
962
- end
963
-
964
- let(:failed_operation) do
965
- authorized_client[:specs, invalid: true].create(session: session)
966
- end
967
-
968
- before do
969
- collection.drop
970
- end
971
-
972
- it_behaves_like 'an operation using a session'
973
- it_behaves_like 'a failed operation using a session'
974
- end
975
- end
976
-
977
- context 'when collation has a strength' do
978
- min_server_fcv '3.4'
979
-
980
- let(:band_collection) do
981
- described_class.new(database, :bands)
982
- end
983
-
984
- before do
985
- band_collection.delete_many
986
- band_collection.insert_many([{ name: "Depeche Mode" }, { name: "New Order" }])
987
- end
988
-
989
- let(:options) do
990
- { collation: { locale: 'en_US', strength: 2 } }
991
- end
992
- let(:band_result) do
993
- band_collection.find({ name: 'DEPECHE MODE' }, options)
994
- end
995
-
996
- it 'finds Capitalize from UPPER CASE' do
997
- expect(band_result.count_documents).to eq(1)
998
- end
999
- end
1000
- end
1001
-
1002
- describe '#drop' do
1003
-
1004
- let(:database) do
1005
- authorized_client.database
1006
- end
1007
-
1008
- let(:collection) do
1009
- described_class.new(database, :specs)
1010
- end
1011
-
1012
- context 'when the collection exists' do
1013
-
1014
- before do
1015
- authorized_client[:specs].drop
1016
- collection.create
1017
- # wait for the collection to be created
1018
- sleep 0.4
1019
- end
1020
-
1021
- context 'when a session is provided' do
1022
-
1023
- let(:operation) do
1024
- collection.drop(session: session)
1025
- end
1026
-
1027
- let(:failed_operation) do
1028
- collection.with(write: INVALID_WRITE_CONCERN).drop(session: session)
1029
- end
1030
-
1031
- let(:session) do
1032
- authorized_client.start_session
1033
- end
1034
-
1035
- let(:client) do
1036
- authorized_client
1037
- end
1038
-
1039
- it_behaves_like 'an operation using a session'
1040
-
1041
- context 'can set write concern' do
1042
- require_set_write_concern
1043
-
1044
- it_behaves_like 'a failed operation using a session'
1045
- end
1046
- end
1047
-
1048
- context 'when the collection does not have a write concern set' do
1049
-
1050
- let!(:response) do
1051
- collection.drop
1052
- end
1053
-
1054
- it 'executes the command' do
1055
- expect(response).to be_successful
1056
- end
1057
-
1058
- it 'drops the collection from the database' do
1059
- expect(database.collection_names).to_not include('specs')
1060
- end
1061
-
1062
- context 'when the collection does not exist' do
1063
- require_set_write_concern
1064
-
1065
- it 'does not raise an error' do
1066
- expect(database['non-existent-coll'].drop).to be(false)
1067
- end
1068
- end
1069
- end
1070
-
1071
- context 'when the collection has a write concern' do
1072
-
1073
- let(:write_options) do
1074
- {
1075
- write: INVALID_WRITE_CONCERN
1076
- }
1077
- end
1078
-
1079
- let(:collection_with_write_options) do
1080
- collection.with(write_options)
1081
- end
1082
-
1083
- context 'when the server supports write concern on the drop command' do
1084
- min_server_fcv '3.4'
1085
- require_set_write_concern
1086
-
1087
- it 'applies the write concern' do
1088
- expect{
1089
- collection_with_write_options.drop
1090
- }.to raise_exception(Mongo::Error::OperationFailure)
1091
- end
1092
- end
1093
-
1094
- context 'when write concern passed in as an option' do
1095
- min_server_fcv '3.4'
1096
- require_set_write_concern
1097
-
1098
- let(:events) do
1099
- subscriber.command_started_events('drop')
1100
- end
1101
-
1102
- let(:options) do
1103
- { write_concern: {w: 1} }
1104
- end
1105
-
1106
- let!(:collection) do
1107
- authorized_collection.with(options)
1108
- end
1109
-
1110
- let!(:command) do
1111
- Utils.get_command_event(authorized_client, 'drop') do |client|
1112
- collection.drop({ write_concern: {w: 0} })
1113
- end.command
1114
- end
1115
-
1116
- it 'applies the write concern passed in as an option' do
1117
- expect(events.length).to eq(1)
1118
- expect(command[:writeConcern][:w]).to eq(0)
1119
- end
1120
- end
1121
-
1122
- context 'when the server does not support write concern on the drop command' do
1123
- max_server_version '3.2'
677
+ describe '#inspect' do
1124
678
 
1125
- it 'does not apply the write concern' do
1126
- expect(collection_with_write_options.drop).to be_successful
1127
- end
1128
- end
1129
- end
679
+ it 'includes the object id' do
680
+ expect(authorized_collection.inspect).to include(authorized_collection.object_id.to_s)
1130
681
  end
1131
682
 
1132
- context 'when the collection does not exist' do
1133
- require_set_write_concern
1134
-
1135
- before do
1136
- begin
1137
- collection.drop
1138
- rescue Mongo::Error::OperationFailure
1139
- end
1140
- end
1141
-
1142
- it 'returns false' do
1143
- expect(collection.drop).to be(false)
1144
- end
1145
- end
1146
- end
1147
-
1148
- describe '#find' do
1149
-
1150
- describe 'updating cluster time' do
1151
-
1152
- let(:operation) do
1153
- client[TEST_COLL].find.first
1154
- end
1155
-
1156
- let(:operation_with_session) do
1157
- client[TEST_COLL].find({}, session: session).first
1158
- end
1159
-
1160
- let(:second_operation) do
1161
- client[TEST_COLL].find({}, session: session).first
1162
- end
1163
-
1164
- it_behaves_like 'an operation updating cluster time'
1165
- end
1166
-
1167
- context 'when provided a filter' do
1168
-
1169
- let(:view) do
1170
- authorized_collection.find(name: 1)
1171
- end
1172
-
1173
- it 'returns a authorized_collection view for the filter' do
1174
- expect(view.filter).to eq('name' => 1)
1175
- end
1176
- end
1177
-
1178
- context 'when provided no filter' do
1179
-
1180
- let(:view) do
1181
- authorized_collection.find
1182
- end
1183
-
1184
- it 'returns a authorized_collection view with an empty filter' do
1185
- expect(view.filter).to be_empty
1186
- end
1187
- end
1188
-
1189
- context 'when providing a bad filter' do
1190
-
1191
- let(:view) do
1192
- authorized_collection.find('$or' => [])
1193
- end
1194
-
1195
- it 'raises an exception when iterating' do
1196
- expect {
1197
- view.to_a
1198
- }.to raise_exception(Mongo::Error::OperationFailure)
1199
- end
1200
- end
1201
-
1202
- context 'when iterating the authorized_collection view' do
1203
-
1204
- before do
1205
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
1206
- end
1207
-
1208
- let(:view) do
1209
- authorized_collection.find
1210
- end
1211
-
1212
- it 'iterates over the documents' do
1213
- view.each do |document|
1214
- expect(document).to_not be_nil
1215
- end
1216
- end
1217
- end
1218
-
1219
- context 'when the user is not authorized' do
1220
- require_auth
1221
-
1222
- let(:view) do
1223
- unauthorized_collection.find
1224
- end
1225
-
1226
- it 'iterates over the documents' do
1227
- expect {
1228
- view.each{ |document| document }
1229
- }.to raise_error(Mongo::Error::OperationFailure)
1230
- end
1231
- end
1232
-
1233
- context 'when documents contain potential error message fields' do
1234
-
1235
- [ Mongo::Error::ERRMSG, Mongo::Error::ERROR, Mongo::Operation::Result::OK ].each do |field|
1236
-
1237
- context "when the document contains a '#{field}' field" do
1238
-
1239
- let(:value) do
1240
- 'testing'
1241
- end
1242
-
1243
- let(:view) do
1244
- authorized_collection.find
1245
- end
1246
-
1247
- before do
1248
- authorized_collection.insert_one({ field => value })
1249
- end
1250
-
1251
- it 'iterates over the documents' do
1252
- view.each do |document|
1253
- expect(document[field]).to eq(value)
1254
- end
1255
- end
1256
- end
1257
- end
1258
- end
1259
-
1260
- context 'when provided options' do
1261
-
1262
- context 'when a session is provided' do
1263
- require_wired_tiger
1264
-
1265
- let(:operation) do
1266
- authorized_collection.find({}, session: session).to_a
1267
- end
1268
-
1269
- let(:session) do
1270
- authorized_client.start_session
1271
- end
1272
-
1273
- let(:failed_operation) do
1274
- client[authorized_collection.name].find({ '$._id' => 1 }, session: session).to_a
1275
- end
1276
-
1277
- let(:client) do
1278
- authorized_client
1279
- end
1280
-
1281
- it_behaves_like 'an operation using a session'
1282
- it_behaves_like 'a failed operation using a session'
1283
- end
1284
-
1285
- context 'session id' do
1286
- min_server_fcv '3.6'
1287
- require_topology :replica_set, :sharded
1288
- require_wired_tiger
1289
-
1290
- let(:options) do
1291
- { session: session }
1292
- end
1293
-
1294
- let(:session) do
1295
- client.start_session
1296
- end
1297
-
1298
- let(:view) do
1299
- Mongo::Collection::View.new(client[TEST_COLL], selector, view_options)
1300
- end
1301
-
1302
- let(:command) do
1303
- client[TEST_COLL].find({}, session: session).explain
1304
- subscriber.started_events.find { |c| c.command_name == 'explain' }.command
1305
- end
1306
-
1307
- it 'sends the session id' do
1308
- expect(command['lsid']).to eq(session.session_id)
1309
- end
1310
- end
1311
-
1312
- context 'when a session supporting causal consistency is used' do
1313
- require_wired_tiger
1314
-
1315
- let(:operation) do
1316
- collection.find({}, session: session).to_a
1317
- end
1318
-
1319
- let(:command) do
1320
- operation
1321
- subscriber.started_events.find { |cmd| cmd.command_name == 'find' }.command
1322
- end
1323
-
1324
- it_behaves_like 'an operation supporting causally consistent reads'
1325
- end
1326
-
1327
- let(:view) do
1328
- authorized_collection.find({}, options)
1329
- end
1330
-
1331
- context 'when provided :allow_partial_results' do
1332
-
1333
- let(:options) do
1334
- { allow_partial_results: true }
1335
- end
1336
-
1337
- it 'returns a view with :allow_partial_results set' do
1338
- expect(view.options[:allow_partial_results]).to be(options[:allow_partial_results])
1339
- end
1340
- end
1341
-
1342
- context 'when provided :batch_size' do
1343
-
1344
- let(:options) do
1345
- { batch_size: 100 }
1346
- end
1347
-
1348
- it 'returns a view with :batch_size set' do
1349
- expect(view.options[:batch_size]).to eq(options[:batch_size])
1350
- end
1351
- end
1352
-
1353
- context 'when provided :comment' do
1354
-
1355
- let(:options) do
1356
- { comment: 'slow query' }
1357
- end
1358
-
1359
- it 'returns a view with :comment set' do
1360
- expect(view.modifiers[:$comment]).to eq(options[:comment])
1361
- end
1362
- end
1363
-
1364
- context 'when provided :cursor_type' do
1365
-
1366
- let(:options) do
1367
- { cursor_type: :tailable }
1368
- end
1369
-
1370
- it 'returns a view with :cursor_type set' do
1371
- expect(view.options[:cursor_type]).to eq(options[:cursor_type])
1372
- end
1373
- end
1374
-
1375
- context 'when provided :max_time_ms' do
1376
-
1377
- let(:options) do
1378
- { max_time_ms: 500 }
1379
- end
1380
-
1381
- it 'returns a view with :max_time_ms set' do
1382
- expect(view.modifiers[:$maxTimeMS]).to eq(options[:max_time_ms])
1383
- end
1384
- end
1385
-
1386
- context 'when provided :modifiers' do
1387
-
1388
- let(:options) do
1389
- { modifiers: { '$orderby' => Mongo::Index::ASCENDING } }
1390
- end
1391
-
1392
- it 'returns a view with modifiers set' do
1393
- expect(view.modifiers).to eq(options[:modifiers])
1394
- end
1395
-
1396
- it 'dups the modifiers hash' do
1397
- expect(view.modifiers).not_to be(options[:modifiers])
1398
- end
1399
- end
1400
-
1401
- context 'when provided :no_cursor_timeout' do
1402
-
1403
- let(:options) do
1404
- { no_cursor_timeout: true }
1405
- end
1406
-
1407
- it 'returns a view with :no_cursor_timeout set' do
1408
- expect(view.options[:no_cursor_timeout]).to eq(options[:no_cursor_timeout])
1409
- end
1410
- end
1411
-
1412
- context 'when provided :oplog_replay' do
1413
-
1414
- let(:options) do
1415
- { oplog_replay: false }
1416
- end
1417
-
1418
- it 'returns a view with :oplog_replay set' do
1419
- expect(view.options[:oplog_replay]).to eq(options[:oplog_replay])
1420
- end
1421
- end
1422
-
1423
- context 'when provided :projection' do
1424
-
1425
- let(:options) do
1426
- { projection: { 'x' => 1 } }
1427
- end
1428
-
1429
- it 'returns a view with :projection set' do
1430
- expect(view.options[:projection]).to eq(options[:projection])
1431
- end
1432
- end
1433
-
1434
- context 'when provided :skip' do
1435
-
1436
- let(:options) do
1437
- { skip: 5 }
1438
- end
1439
-
1440
- it 'returns a view with :skip set' do
1441
- expect(view.options[:skip]).to eq(options[:skip])
1442
- end
1443
- end
1444
-
1445
- context 'when provided :sort' do
1446
-
1447
- let(:options) do
1448
- { sort: { 'x' => Mongo::Index::ASCENDING } }
1449
- end
1450
-
1451
- it 'returns a view with :sort set' do
1452
- expect(view.modifiers[:$orderby]).to eq(options[:sort])
1453
- end
1454
- end
1455
-
1456
- context 'when provided :collation' do
1457
-
1458
- let(:options) do
1459
- { collation: { 'locale' => 'en_US' } }
1460
- end
1461
-
1462
- it 'returns a view with :collation set' do
1463
- expect(view.options[:collation]).to eq(options[:collation])
1464
- end
1465
- end
1466
- end
1467
- end
1468
-
1469
- describe '#insert_many' do
1470
-
1471
- let(:result) do
1472
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
1473
- end
1474
-
1475
- it 'inserts the documents into the collection' do
1476
- expect(result.inserted_count).to eq(2)
1477
- end
1478
-
1479
- it 'contains the ids in the result' do
1480
- expect(result.inserted_ids.size).to eq(2)
1481
- end
1482
-
1483
- context 'when a session is provided' do
1484
-
1485
- let(:session) do
1486
- authorized_client.start_session
1487
- end
1488
-
1489
- let(:operation) do
1490
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
1491
- end
1492
-
1493
- let(:failed_operation) do
1494
- authorized_collection.insert_many([{ _id: 'test1' }, { _id: 'test1' }], session: session)
1495
- end
1496
-
1497
- let(:client) do
1498
- authorized_client
1499
- end
1500
-
1501
- it_behaves_like 'an operation using a session'
1502
- it_behaves_like 'a failed operation using a session'
1503
- end
1504
-
1505
- context 'when unacknowledged writes is used with an explicit session' do
1506
-
1507
- let(:collection_with_unacknowledged_write_concern) do
1508
- authorized_collection.with(write: { w: 0 })
1509
- end
1510
-
1511
- let(:operation) do
1512
- collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
1513
- end
1514
-
1515
- it_behaves_like 'an explicit session with an unacknowledged write'
1516
- end
1517
-
1518
- context 'when unacknowledged writes is used with an implicit session' do
1519
-
1520
- let(:collection_with_unacknowledged_write_concern) do
1521
- client.with(write: { w: 0 })[TEST_COLL]
1522
- end
1523
-
1524
- let(:operation) do
1525
- collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }])
1526
- end
1527
-
1528
- it_behaves_like 'an implicit session with an unacknowledged write'
1529
- end
1530
-
1531
- context 'when a document contains invalid keys' do
1532
-
1533
- let(:docs) do
1534
- [ { 'first.name' => 'test1' }, { name: 'test2' } ]
1535
- end
1536
-
1537
- it 'raises a BSON::String::IllegalKey exception' do
1538
- expect {
1539
- authorized_collection.insert_many(docs)
1540
- }.to raise_exception(BSON::String::IllegalKey)
1541
- end
1542
- end
1543
-
1544
- context 'when the client has a custom id generator' do
1545
-
1546
- let(:generator) do
1547
- Class.new do
1548
- def generate
1549
- 1
1550
- end
1551
- end.new
1552
- end
1553
-
1554
- let(:custom_client) do
1555
- authorized_client.with(id_generator: generator)
1556
- end
1557
-
1558
- let(:custom_collection) do
1559
- custom_client['custom_id_generator_test_collection']
1560
- end
1561
-
1562
- before do
1563
- custom_collection.delete_many
1564
- custom_collection.insert_many([{ name: 'testing' }])
1565
- expect(custom_collection.count).to eq(1)
1566
- end
1567
-
1568
- it 'inserts with the custom id' do
1569
- expect(custom_collection.count).to eq(1)
1570
- expect(custom_collection.find.first[:_id]).to eq(1)
1571
- end
1572
- end
1573
-
1574
- context 'when the inserts fail' do
1575
-
1576
- let(:result) do
1577
- authorized_collection.insert_many([{ _id: 1 }, { _id: 1 }])
1578
- end
1579
-
1580
- it 'raises an BulkWriteError' do
1581
- expect {
1582
- result
1583
- }.to raise_exception(Mongo::Error::BulkWriteError)
1584
- end
1585
- end
1586
-
1587
- context "when the documents exceed the max bson size" do
1588
-
1589
- let(:documents) do
1590
- [{ '_id' => 1, 'name' => '1'*17000000 }]
1591
- end
1592
-
1593
- it 'raises a MaxBSONSize error' do
1594
- expect {
1595
- authorized_collection.insert_many(documents)
1596
- }.to raise_error(Mongo::Error::MaxBSONSize)
1597
- end
1598
- end
1599
-
1600
- context 'when the documents are sent with OP_MSG' do
1601
- min_server_fcv '3.6'
1602
-
1603
- let(:documents) do
1604
- [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
1605
- end
1606
-
1607
- before do
1608
- authorized_collection.insert_many(documents)
1609
- end
1610
-
1611
- let(:insert_events) do
1612
- subscriber.started_events.select { |e| e.command_name == 'insert' }
1613
- end
1614
-
1615
- it 'sends the documents in one OP_MSG' do
1616
- expect(insert_events.size).to eq(1)
1617
- expect(insert_events[0].command['documents']).to eq(documents)
1618
- end
1619
- end
1620
-
1621
- context 'when collection has a validator' do
1622
- min_server_fcv '3.2'
1623
-
1624
- around(:each) do |spec|
1625
- authorized_client[:validating].drop
1626
- authorized_client[:validating,
1627
- :validator => { :a => { '$exists' => true } }].tap do |c|
1628
- c.create
1629
- end
1630
- spec.run
1631
- collection_with_validator.drop
1632
- end
1633
-
1634
- context 'when the document is valid' do
1635
-
1636
- let(:result) do
1637
- collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
1638
- end
1639
-
1640
- it 'inserts successfully' do
1641
- expect(result.inserted_count).to eq(2)
1642
- end
1643
- end
1644
-
1645
- context 'when the document is invalid' do
1646
-
1647
- context 'when bypass_document_validation is not set' do
1648
-
1649
- let(:result2) do
1650
- collection_with_validator.insert_many([{ x: 1 }, { x: 2 }])
1651
- end
1652
-
1653
- it 'raises a BulkWriteError' do
1654
- expect {
1655
- result2
1656
- }.to raise_exception(Mongo::Error::BulkWriteError)
1657
- end
1658
- end
1659
-
1660
- context 'when bypass_document_validation is true' do
1661
-
1662
- let(:result3) do
1663
- collection_with_validator.insert_many(
1664
- [{ x: 1 }, { x: 2 }], :bypass_document_validation => true)
1665
- end
1666
-
1667
- it 'inserts successfully' do
1668
- expect(result3.inserted_count).to eq(2)
1669
- end
1670
- end
1671
- end
1672
- end
1673
-
1674
- context 'when unacknowledged writes is used' do
1675
-
1676
- let(:collection_with_unacknowledged_write_concern) do
1677
- authorized_collection.with(write: { w: 0 })
1678
- end
1679
-
1680
- let(:result) do
1681
- collection_with_unacknowledged_write_concern.insert_many([{ _id: 1 }, { _id: 1 }])
1682
- end
1683
-
1684
- it 'does not raise an exception' do
1685
- expect(result.inserted_count).to be(0)
1686
- end
1687
- end
1688
-
1689
- context 'when various options passed in' do
1690
- # w: 2 requires a replica set
1691
- require_topology :replica_set
1692
-
1693
- # https://jira.mongodb.org/browse/RUBY-2306
1694
- min_server_fcv '3.6'
1695
-
1696
- let(:session) do
1697
- authorized_client.start_session
1698
- end
1699
-
1700
- let(:events) do
1701
- subscriber.command_started_events('insert')
1702
- end
1703
-
1704
- let(:collection) do
1705
- authorized_collection.with(write_concern: {w: 2})
1706
- end
1707
-
1708
- let!(:command) do
1709
- Utils.get_command_event(authorized_client, 'insert') do |client|
1710
- collection.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session,
1711
- write_concern: {w: 1}, bypass_document_validation: true)
1712
- end.command
1713
- end
1714
-
1715
- it 'inserts many successfully with correct options sent to server' do
1716
- expect(events.length).to eq(1)
1717
- expect(command[:writeConcern]).to_not be_nil
1718
- expect(command[:writeConcern][:w]).to eq(1)
1719
- expect(command[:bypassDocumentValidation]).to be(true)
1720
- end
1721
- end
1722
- end
1723
-
1724
- describe '#insert_one' do
1725
-
1726
- describe 'updating cluster time' do
1727
-
1728
- let(:operation) do
1729
- client[TEST_COLL].insert_one({ name: 'testing' })
1730
- end
1731
-
1732
- let(:operation_with_session) do
1733
- client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1734
- end
1735
-
1736
- let(:second_operation) do
1737
- client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1738
- end
1739
-
1740
- it_behaves_like 'an operation updating cluster time'
1741
- end
1742
-
1743
- let(:result) do
1744
- authorized_collection.insert_one({ name: 'testing' })
1745
- end
1746
-
1747
- it 'inserts the document into the collection'do
1748
- expect(result.written_count).to eq(1)
1749
- end
1750
-
1751
- it 'contains the id in the result' do
1752
- expect(result.inserted_id).to_not be_nil
1753
- end
1754
-
1755
- context 'when a session is provided' do
1756
-
1757
- let(:session) do
1758
- authorized_client.start_session
1759
- end
1760
-
1761
- let(:operation) do
1762
- authorized_collection.insert_one({ name: 'testing' }, session: session)
1763
- end
1764
-
1765
- let(:failed_operation) do
1766
- authorized_collection.insert_one({ _id: 'testing' })
1767
- authorized_collection.insert_one({ _id: 'testing' }, session: session)
1768
- end
1769
-
1770
- let(:client) do
1771
- authorized_client
1772
- end
1773
-
1774
- it_behaves_like 'an operation using a session'
1775
- it_behaves_like 'a failed operation using a session'
1776
- end
1777
-
1778
- context 'when unacknowledged writes is used with an explicit session' do
1779
-
1780
- let(:collection_with_unacknowledged_write_concern) do
1781
- authorized_collection.with(write: { w: 0 })
1782
- end
1783
-
1784
- let(:operation) do
1785
- collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' }, session: session)
1786
- end
1787
-
1788
- it_behaves_like 'an explicit session with an unacknowledged write'
1789
- end
1790
-
1791
- context 'when unacknowledged writes is used with an implicit session' do
1792
-
1793
- let(:collection_with_unacknowledged_write_concern) do
1794
- client.with(write: { w: 0 })[TEST_COLL]
1795
- end
1796
-
1797
- let(:operation) do
1798
- collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' })
1799
- end
1800
-
1801
- it_behaves_like 'an implicit session with an unacknowledged write'
1802
- end
1803
-
1804
- context 'when various options passed in' do
1805
- # https://jira.mongodb.org/browse/RUBY-2306
1806
- min_server_fcv '3.6'
1807
-
1808
- let(:session) do
1809
- authorized_client.start_session
1810
- end
1811
-
1812
- let(:events) do
1813
- subscriber.command_started_events('insert')
1814
- end
1815
-
1816
- let(:collection) do
1817
- authorized_collection.with(write_concern: {w: 3})
1818
- end
1819
-
1820
- let!(:command) do
1821
- Utils.get_command_event(authorized_client, 'insert') do |client|
1822
- collection.insert_one({name: 'test1'}, session: session, write_concern: {w: 1},
1823
- bypass_document_validation: true)
1824
- end.command
1825
- end
1826
-
1827
- it 'inserts one successfully with correct options sent to server' do
1828
- expect(events.length).to eq(1)
1829
- expect(command[:writeConcern]).to_not be_nil
1830
- expect(command[:writeConcern][:w]).to eq(1)
1831
- expect(command[:bypassDocumentValidation]).to be(true)
1832
- end
1833
- end
1834
-
1835
- context 'when the document contains invalid keys' do
1836
-
1837
- let(:doc) do
1838
- { 'testing.test' => 'value' }
1839
- end
1840
-
1841
- it 'raises a BSON::String::IllegalKey exception' do
1842
- expect {
1843
- authorized_collection.insert_one(doc)
1844
- }.to raise_exception(BSON::String::IllegalKey)
1845
- end
1846
- end
1847
-
1848
- context 'when the document is nil' do
1849
- let(:result) do
1850
- authorized_collection.insert_one(nil)
1851
- end
1852
-
1853
- it 'raises an ArgumentError' do
1854
- expect {
1855
- result
1856
- }.to raise_error(ArgumentError, "Document to be inserted cannot be nil")
1857
- end
1858
- end
1859
-
1860
- context 'when the insert fails' do
1861
-
1862
- let(:result) do
1863
- authorized_collection.insert_one(_id: 1)
1864
- authorized_collection.insert_one(_id: 1)
1865
- end
1866
-
1867
- it 'raises an OperationFailure' do
1868
- expect {
1869
- result
1870
- }.to raise_exception(Mongo::Error::OperationFailure)
1871
- end
1872
- end
1873
-
1874
- context 'when the client has a custom id generator' do
1875
-
1876
- let(:generator) do
1877
- Class.new do
1878
- def generate
1879
- 1
1880
- end
1881
- end.new
1882
- end
1883
-
1884
- let(:custom_client) do
1885
- authorized_client.with(id_generator: generator)
1886
- end
1887
-
1888
- let(:custom_collection) do
1889
- custom_client[TEST_COLL]
1890
- end
1891
-
1892
- before do
1893
- custom_collection.delete_many
1894
- custom_collection.insert_one({ name: 'testing' })
1895
- end
1896
-
1897
- it 'inserts with the custom id' do
1898
- expect(custom_collection.find.first[:_id]).to eq(1)
1899
- end
1900
- end
1901
-
1902
- context 'when collection has a validator' do
1903
- min_server_fcv '3.2'
1904
-
1905
- around(:each) do |spec|
1906
- authorized_client[:validating,
1907
- :validator => { :a => { '$exists' => true } }].tap do |c|
1908
- c.create
1909
- end
1910
- spec.run
1911
- collection_with_validator.drop
1912
- end
1913
-
1914
- context 'when the document is valid' do
1915
-
1916
- let(:result) do
1917
- collection_with_validator.insert_one({ a: 1 })
1918
- end
1919
-
1920
- it 'inserts successfully' do
1921
- expect(result.written_count).to eq(1)
1922
- end
1923
- end
1924
-
1925
- context 'when the document is invalid' do
1926
-
1927
- context 'when bypass_document_validation is not set' do
1928
-
1929
- let(:result2) do
1930
- collection_with_validator.insert_one({ x: 1 })
1931
- end
1932
-
1933
- it 'raises a OperationFailure' do
1934
- expect {
1935
- result2
1936
- }.to raise_exception(Mongo::Error::OperationFailure)
1937
- end
1938
- end
1939
-
1940
- context 'when bypass_document_validation is true' do
1941
-
1942
- let(:result3) do
1943
- collection_with_validator.insert_one(
1944
- { x: 1 }, :bypass_document_validation => true)
1945
- end
1946
-
1947
- it 'inserts successfully' do
1948
- expect(result3.written_count).to eq(1)
1949
- end
1950
- end
1951
- end
1952
- end
1953
- end
1954
-
1955
- describe '#bulk_write' do
1956
-
1957
- context 'when various options passed in' do
1958
- min_server_fcv '3.2'
1959
- require_topology :replica_set
1960
-
1961
- # https://jira.mongodb.org/browse/RUBY-2306
1962
- min_server_fcv '3.6'
1963
-
1964
- let(:requests) do
1965
- [
1966
- { insert_one: { name: "anne" }},
1967
- { insert_one: { name: "bob" }},
1968
- { insert_one: { name: "charlie" }}
1969
- ]
1970
- end
1971
-
1972
- let(:session) do
1973
- authorized_client.start_session
1974
- end
1975
-
1976
- let!(:command) do
1977
- Utils.get_command_event(authorized_client, 'insert') do |client|
1978
- collection.bulk_write(requests, session: session, write_concern: {w: 1},
1979
- bypass_document_validation: true)
1980
- end.command
1981
- end
1982
-
1983
- let(:events) do
1984
- subscriber.command_started_events('insert')
1985
- end
1986
-
1987
- let(:collection) do
1988
- authorized_collection.with(write_concern: {w: 2})
1989
- end
1990
-
1991
- it 'inserts successfully with correct options sent to server' do
1992
- expect(collection.count).to eq(3)
1993
- expect(events.length).to eq(1)
1994
- expect(command[:writeConcern]).to_not be_nil
1995
- expect(command[:writeConcern][:w]).to eq(1)
1996
- expect(command[:bypassDocumentValidation]).to eq(true)
1997
- end
1998
- end
1999
- end
2000
-
2001
- describe '#inspect' do
2002
-
2003
- it 'includes the object id' do
2004
- expect(authorized_collection.inspect).to include(authorized_collection.object_id.to_s)
2005
- end
2006
-
2007
- it 'includes the namespace' do
2008
- expect(authorized_collection.inspect).to include(authorized_collection.namespace)
2009
- end
2010
- end
2011
-
2012
- describe '#indexes' do
2013
-
2014
- let(:index_spec) do
2015
- { name: 1 }
2016
- end
2017
-
2018
- let(:batch_size) { nil }
2019
-
2020
- let(:index_names) do
2021
- authorized_collection.indexes(batch_size: batch_size).collect { |i| i['name'] }
2022
- end
2023
-
2024
- before do
2025
- authorized_collection.indexes.create_one(index_spec, unique: true)
2026
- end
2027
-
2028
- it 'returns a list of indexes' do
2029
- expect(index_names).to include(*'name_1', '_id_')
2030
- end
2031
-
2032
- context 'when a session is provided' do
2033
- require_wired_tiger
2034
-
2035
- let(:session) do
2036
- authorized_client.start_session
2037
- end
2038
-
2039
- let(:operation) do
2040
- authorized_collection.indexes(batch_size: batch_size, session: session).collect { |i| i['name'] }
2041
- end
2042
-
2043
- let(:failed_operation) do
2044
- authorized_collection.indexes(batch_size: -100, session: session).collect { |i| i['name'] }
2045
- end
2046
-
2047
- let(:client) do
2048
- authorized_client
2049
- end
2050
-
2051
- it_behaves_like 'an operation using a session'
2052
- it_behaves_like 'a failed operation using a session'
2053
- end
2054
-
2055
- context 'when batch size is specified' do
2056
-
2057
- let(:batch_size) { 1 }
2058
-
2059
- it 'returns a list of indexes' do
2060
- expect(index_names).to include(*'name_1', '_id_')
2061
- end
2062
- end
2063
- end
2064
-
2065
- describe '#aggregate' do
2066
-
2067
- describe 'updating cluster time' do
2068
-
2069
- let(:operation) do
2070
- client[TEST_COLL].aggregate([]).first
2071
- end
2072
-
2073
- let(:operation_with_session) do
2074
- client[TEST_COLL].aggregate([], session: session).first
2075
- end
2076
-
2077
- let(:second_operation) do
2078
- client[TEST_COLL].aggregate([], session: session).first
2079
- end
2080
-
2081
- it_behaves_like 'an operation updating cluster time'
2082
- end
2083
-
2084
- context 'when a session supporting causal consistency is used' do
2085
- require_wired_tiger
2086
-
2087
- let(:operation) do
2088
- collection.aggregate([], session: session).first
2089
- end
2090
-
2091
- let(:command) do
2092
- operation
2093
- subscriber.started_events.find { |cmd| cmd.command_name == 'aggregate' }.command
2094
- end
2095
-
2096
- it_behaves_like 'an operation supporting causally consistent reads'
2097
- end
2098
-
2099
- it 'returns an Aggregation object' do
2100
- expect(authorized_collection.aggregate([])).to be_a(Mongo::Collection::View::Aggregation)
2101
- end
2102
-
2103
- context 'when options are provided' do
2104
-
2105
- let(:options) do
2106
- { :allow_disk_use => true, :bypass_document_validation => true }
2107
- end
2108
-
2109
- it 'sets the options on the Aggregation object' do
2110
- expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
2111
- end
2112
-
2113
- context 'when the :comment option is provided' do
2114
-
2115
- let(:options) do
2116
- { :comment => 'testing' }
2117
- end
2118
-
2119
- it 'sets the options on the Aggregation object' do
2120
- expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
2121
- end
2122
- end
2123
-
2124
- context 'when a session is provided' do
2125
-
2126
- let(:session) do
2127
- authorized_client.start_session
2128
- end
2129
-
2130
- let(:operation) do
2131
- authorized_collection.aggregate([], session: session).to_a
2132
- end
2133
-
2134
- let(:failed_operation) do
2135
- authorized_collection.aggregate([ { '$invalid' => 1 }], session: session).to_a
2136
- end
2137
-
2138
- let(:client) do
2139
- authorized_client
2140
- end
2141
-
2142
- it_behaves_like 'an operation using a session'
2143
- it_behaves_like 'a failed operation using a session'
2144
- end
2145
-
2146
- context 'when a hint is provided' do
2147
-
2148
- let(:options) do
2149
- { 'hint' => { 'y' => 1 } }
2150
- end
2151
-
2152
- it 'sets the options on the Aggregation object' do
2153
- expect(authorized_collection.aggregate([], options).options).to eq(options)
2154
- end
2155
- end
2156
-
2157
- context 'when collation is provided' do
2158
-
2159
- before do
2160
- authorized_collection.insert_many([ { name: 'bang' }, { name: 'bang' }])
2161
- end
2162
-
2163
- let(:pipeline) do
2164
- [{ "$match" => { "name" => "BANG" } }]
2165
- end
2166
-
2167
- let(:options) do
2168
- { collation: { locale: 'en_US', strength: 2 } }
2169
- end
2170
-
2171
- let(:result) do
2172
- authorized_collection.aggregate(pipeline, options).collect { |doc| doc['name']}
2173
- end
2174
-
2175
- context 'when the server selected supports collations' do
2176
- min_server_fcv '3.4'
2177
-
2178
- it 'applies the collation' do
2179
- expect(result).to eq(['bang', 'bang'])
2180
- end
2181
- end
2182
-
2183
- context 'when the server selected does not support collations' do
2184
- max_server_version '3.2'
2185
-
2186
- it 'raises an exception' do
2187
- expect {
2188
- result
2189
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2190
- end
2191
-
2192
- context 'when a String key is used' do
2193
-
2194
- let(:options) do
2195
- { 'collation' => { locale: 'en_US', strength: 2 } }
2196
- end
2197
-
2198
- it 'raises an exception' do
2199
- expect {
2200
- result
2201
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2202
- end
2203
- end
2204
- end
2205
- end
2206
- end
2207
- end
2208
-
2209
- describe '#count_documents' do
2210
-
2211
- before do
2212
- authorized_collection.delete_many
2213
- end
2214
-
2215
- context 'no argument provided' do
2216
-
2217
- context 'when collection is empty' do
2218
- it 'returns 0 matching documents' do
2219
- expect(authorized_collection.count_documents).to eq(0)
2220
- end
2221
- end
2222
-
2223
- context 'when collection is not empty' do
2224
-
2225
- let(:documents) do
2226
- documents = []
2227
- 1.upto(10) do |index|
2228
- documents << { key: 'a', _id: "in#{index}" }
2229
- end
2230
- documents
2231
- end
2232
-
2233
- before do
2234
- authorized_collection.insert_many(documents)
2235
- end
2236
-
2237
- it 'returns 10 matching documents' do
2238
- expect(authorized_collection.count_documents).to eq(10)
2239
- end
2240
- end
2241
- end
2242
-
2243
- context 'when transactions are enabled' do
2244
- require_wired_tiger
2245
- require_transaction_support
2246
-
2247
- before do
2248
- # Ensure that the collection is created
2249
- authorized_collection.insert_one(x: 1)
2250
- authorized_collection.delete_many({})
2251
- end
2252
-
2253
- let(:session) do
2254
- authorized_client.start_session
2255
- end
2256
-
2257
- it 'successfully starts a transaction and executes a transaction' do
2258
- session.start_transaction
2259
- expect(
2260
- session.instance_variable_get(:@state)
2261
- ).to eq(Mongo::Session::STARTING_TRANSACTION_STATE)
2262
-
2263
- expect(authorized_collection.count_documents({}, { session: session })).to eq(0)
2264
- expect(
2265
- session.instance_variable_get(:@state)
2266
- ).to eq(Mongo::Session::TRANSACTION_IN_PROGRESS_STATE)
2267
-
2268
- authorized_collection.insert_one({ x: 1 }, { session: session })
2269
- expect(authorized_collection.count_documents({}, { session: session })).to eq(1)
2270
-
2271
- session.commit_transaction
2272
- expect(
2273
- session.instance_variable_get(:@state)
2274
- ).to eq(Mongo::Session::TRANSACTION_COMMITTED_STATE)
2275
- end
2276
- end
2277
- end
2278
-
2279
- describe '#count' do
2280
-
2281
- let(:documents) do
2282
- (1..10).map{ |i| { field: "test#{i}" }}
2283
- end
2284
-
2285
- before do
2286
- authorized_collection.insert_many(documents)
2287
- end
2288
-
2289
- it 'returns an integer count' do
2290
- expect(authorized_collection.count).to eq(10)
2291
- end
2292
-
2293
- context 'when options are provided' do
2294
-
2295
- it 'passes the options to the count' do
2296
- expect(authorized_collection.count({}, limit: 5)).to eq(5)
2297
- end
2298
-
2299
- context 'when a session is provided' do
2300
- require_wired_tiger
2301
-
2302
- let(:session) do
2303
- authorized_client.start_session
2304
- end
2305
-
2306
- let(:operation) do
2307
- authorized_collection.count({}, session: session)
2308
- end
2309
-
2310
- let(:failed_operation) do
2311
- authorized_collection.count({ '$._id' => 1 }, session: session)
2312
- end
2313
-
2314
- let(:client) do
2315
- authorized_client
2316
- end
2317
-
2318
- it_behaves_like 'an operation using a session'
2319
- it_behaves_like 'a failed operation using a session'
2320
- end
2321
-
2322
- context 'when a session supporting causal consistency is used' do
2323
- require_wired_tiger
2324
-
2325
- let(:operation) do
2326
- collection.count({}, session: session)
2327
- end
2328
-
2329
- let(:command) do
2330
- operation
2331
- subscriber.started_events.find { |cmd| cmd.command_name == 'count' }.command
2332
- end
2333
-
2334
- it_behaves_like 'an operation supporting causally consistent reads'
2335
- end
2336
-
2337
- context 'when a collation is specified' do
2338
-
2339
- let(:selector) do
2340
- { name: 'BANG' }
2341
- end
2342
-
2343
- let(:result) do
2344
- authorized_collection.count(selector, options)
2345
- end
2346
-
2347
- before do
2348
- authorized_collection.insert_one(name: 'bang')
2349
- end
2350
-
2351
- let(:options) do
2352
- { collation: { locale: 'en_US', strength: 2 } }
2353
- end
2354
-
2355
- context 'when the server selected supports collations' do
2356
- min_server_fcv '3.4'
2357
-
2358
- it 'applies the collation to the count' do
2359
- expect(result).to eq(1)
2360
- end
2361
- end
2362
-
2363
- context 'when the server selected does not support collations' do
2364
- max_server_version '3.2'
2365
-
2366
- it 'raises an exception' do
2367
- expect {
2368
- result
2369
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2370
- end
2371
-
2372
- context 'when a String key is used' do
2373
-
2374
- let(:options) do
2375
- { 'collation' => { locale: 'en_US', strength: 2 } }
2376
- end
2377
-
2378
- it 'raises an exception' do
2379
- expect {
2380
- result
2381
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2382
- end
2383
- end
2384
- end
2385
- end
2386
- end
2387
- end
2388
-
2389
- describe '#distinct' do
2390
-
2391
- let(:documents) do
2392
- (1..3).map{ |i| { field: "test#{i}" }}
2393
- end
2394
-
2395
- before do
2396
- authorized_collection.insert_many(documents)
2397
- end
2398
-
2399
- it 'returns the distinct values' do
2400
- expect(authorized_collection.distinct(:field).sort).to eq([ 'test1', 'test2', 'test3' ])
2401
- end
2402
-
2403
- context 'when a selector is provided' do
2404
-
2405
- it 'returns the distinct values' do
2406
- expect(authorized_collection.distinct(:field, field: 'test1')).to eq([ 'test1' ])
2407
- end
2408
- end
2409
-
2410
- context 'when options are provided' do
2411
-
2412
- it 'passes the options to the distinct command' do
2413
- expect(authorized_collection.distinct(:field, {}, max_time_ms: 100).sort).to eq([ 'test1', 'test2', 'test3' ])
2414
- end
2415
-
2416
- context 'when a session is provided' do
2417
- require_wired_tiger
2418
-
2419
- let(:session) do
2420
- authorized_client.start_session
2421
- end
2422
-
2423
- let(:operation) do
2424
- authorized_collection.distinct(:field, {}, session: session)
2425
- end
2426
-
2427
- let(:failed_operation) do
2428
- authorized_collection.distinct(:field, { '$._id' => 1 }, session: session)
2429
- end
2430
-
2431
- let(:client) do
2432
- authorized_client
2433
- end
2434
-
2435
- it_behaves_like 'an operation using a session'
2436
- it_behaves_like 'a failed operation using a session'
2437
- end
2438
- end
2439
-
2440
- context 'when a session supporting causal consistency is used' do
2441
- require_wired_tiger
2442
-
2443
- let(:operation) do
2444
- collection.distinct(:field, {}, session: session)
2445
- end
2446
-
2447
- let(:command) do
2448
- operation
2449
- subscriber.started_events.find { |cmd| cmd.command_name == 'distinct' }.command
2450
- end
2451
-
2452
- it_behaves_like 'an operation supporting causally consistent reads'
2453
- end
2454
-
2455
- context 'when a collation is specified' do
2456
-
2457
- let(:result) do
2458
- authorized_collection.distinct(:name, {}, options)
2459
- end
2460
-
2461
- before do
2462
- authorized_collection.insert_one(name: 'bang')
2463
- authorized_collection.insert_one(name: 'BANG')
2464
- end
2465
-
2466
- let(:options) do
2467
- { collation: { locale: 'en_US', strength: 2 } }
2468
- end
2469
-
2470
- context 'when the server selected supports collations' do
2471
- min_server_fcv '3.4'
2472
-
2473
- it 'applies the collation to the distinct' do
2474
- expect(result).to eq(['bang'])
2475
- end
2476
- end
2477
-
2478
- context 'when the server selected does not support collations' do
2479
- max_server_version '3.2'
2480
-
2481
- it 'raises an exception' do
2482
- expect {
2483
- result
2484
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2485
- end
2486
-
2487
- context 'when a String key is used' do
2488
-
2489
- let(:options) do
2490
- { 'collation' => { locale: 'en_US', strength: 2 } }
2491
- end
2492
-
2493
- it 'raises an exception' do
2494
- expect {
2495
- result
2496
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2497
- end
2498
- end
2499
- end
2500
- end
2501
-
2502
- context 'when a collation is not specified' do
2503
-
2504
- let(:result) do
2505
- authorized_collection.distinct(:name)
2506
- end
2507
-
2508
- before do
2509
- authorized_collection.insert_one(name: 'bang')
2510
- authorized_collection.insert_one(name: 'BANG')
2511
- end
2512
-
2513
- it 'does not apply the collation to the distinct' do
2514
- expect(result).to match_array(['bang', 'BANG'])
2515
- end
2516
- end
2517
- end
2518
-
2519
- describe '#delete_one' do
2520
-
2521
- context 'when a selector was provided' do
2522
-
2523
- let(:selector) do
2524
- { field: 'test1' }
2525
- end
2526
-
2527
- before do
2528
- authorized_collection.insert_many([
2529
- { field: 'test1' },
2530
- { field: 'test1' },
2531
- { field: 'test1' }
2532
- ])
2533
- end
2534
-
2535
- let(:response) do
2536
- authorized_collection.delete_one(selector)
2537
- end
2538
-
2539
- it 'deletes the first matching document in the collection' do
2540
- expect(response.deleted_count).to eq(1)
2541
- end
2542
- end
2543
-
2544
- context 'when no selector was provided' do
2545
-
2546
- before do
2547
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
2548
- end
2549
-
2550
- let(:response) do
2551
- authorized_collection.delete_one
2552
- end
2553
-
2554
- it 'deletes the first document in the collection' do
2555
- expect(response.deleted_count).to eq(1)
2556
- end
2557
- end
2558
-
2559
- context 'when the delete fails' do
2560
- require_topology :single
2561
-
2562
- let(:result) do
2563
- collection_invalid_write_concern.delete_one
2564
- end
2565
-
2566
- it 'raises an OperationFailure' do
2567
- expect {
2568
- result
2569
- }.to raise_exception(Mongo::Error::OperationFailure)
2570
- end
2571
- end
2572
-
2573
- context 'when a session is provided' do
2574
-
2575
- let(:session) do
2576
- authorized_client.start_session
2577
- end
2578
-
2579
- let(:operation) do
2580
- authorized_collection.delete_one({}, session: session)
2581
- end
2582
-
2583
- let(:failed_operation) do
2584
- authorized_collection.delete_one({ '$._id' => 1}, session: session)
2585
- end
2586
-
2587
- let(:client) do
2588
- authorized_client
2589
- end
2590
-
2591
- it_behaves_like 'an operation using a session'
2592
- it_behaves_like 'a failed operation using a session'
2593
- end
2594
-
2595
- context 'when unacknowledged writes is used' do
2596
-
2597
- let(:collection_with_unacknowledged_write_concern) do
2598
- authorized_collection.with(write: { w: 0 })
2599
- end
2600
-
2601
- let(:operation) do
2602
- collection_with_unacknowledged_write_concern.delete_one({}, session: session)
2603
- end
2604
-
2605
- it_behaves_like 'an explicit session with an unacknowledged write'
2606
- end
2607
-
2608
- context 'when unacknowledged writes is used with an implicit session' do
2609
-
2610
- let(:collection_with_unacknowledged_write_concern) do
2611
- client.with(write: { w: 0 })[TEST_COLL]
2612
- end
2613
-
2614
- let(:operation) do
2615
- collection_with_unacknowledged_write_concern.delete_one
2616
- end
2617
-
2618
- it_behaves_like 'an implicit session with an unacknowledged write'
2619
- end
2620
-
2621
- context 'when a collation is provided' do
2622
-
2623
- let(:selector) do
2624
- { name: 'BANG' }
2625
- end
2626
-
2627
- let(:result) do
2628
- authorized_collection.delete_one(selector, options)
2629
- end
2630
-
2631
- before do
2632
- authorized_collection.insert_one(name: 'bang')
2633
- end
2634
-
2635
- let(:options) do
2636
- { collation: { locale: 'en_US', strength: 2 } }
2637
- end
2638
-
2639
- context 'when the server selected supports collations' do
2640
- min_server_fcv '3.4'
2641
-
2642
- it 'applies the collation' do
2643
- expect(result.written_count).to eq(1)
2644
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
2645
- end
2646
-
2647
- context 'when unacknowledged writes is used' do
2648
-
2649
- let(:collection_with_unacknowledged_write_concern) do
2650
- authorized_collection.with(write: { w: 0 })
2651
- end
2652
-
2653
- let(:result) do
2654
- collection_with_unacknowledged_write_concern.delete_one(selector, options)
2655
- end
2656
-
2657
- it 'raises an exception' do
2658
- expect {
2659
- result
2660
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2661
- end
2662
-
2663
- context 'when a String key is used' do
2664
-
2665
- let(:options) do
2666
- { 'collation' => { locale: 'en_US', strength: 2 } }
2667
- end
2668
-
2669
- it 'raises an exception' do
2670
- expect {
2671
- result
2672
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2673
- end
2674
- end
2675
- end
2676
- end
2677
-
2678
- context 'when the server selected does not support collations' do
2679
- max_server_version '3.2'
2680
-
2681
- it 'raises an exception' do
2682
- expect {
2683
- result
2684
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2685
- end
2686
-
2687
- context 'when a String key is used' do
2688
-
2689
- let(:options) do
2690
- { 'collation' => { locale: 'en_US', strength: 2 } }
2691
- end
2692
-
2693
- it 'raises an exception' do
2694
- expect {
2695
- result
2696
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2697
- end
2698
- end
2699
- end
2700
- end
2701
-
2702
- context 'when collation is not specified' do
2703
-
2704
- let(:selector) do
2705
- { name: 'BANG' }
2706
- end
2707
-
2708
- let(:result) do
2709
- authorized_collection.delete_one(selector)
2710
- end
2711
-
2712
- before do
2713
- authorized_collection.insert_one(name: 'bang')
2714
- end
2715
-
2716
- it 'does not apply the collation' do
2717
- expect(result.written_count).to eq(0)
2718
- expect(authorized_collection.find(name: 'bang').count).to eq(1)
2719
- end
2720
- end
2721
-
2722
- context 'when various options passed in' do
2723
- # w: 2 requires a replica set
2724
- require_topology :replica_set
2725
-
2726
- # https://jira.mongodb.org/browse/RUBY-2306
2727
- min_server_fcv '3.6'
2728
-
2729
- before do
2730
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
2731
- end
2732
-
2733
- let(:selector) do
2734
- {name: 'test2'}
2735
- end
2736
-
2737
- let(:session) do
2738
- authorized_client.start_session
2739
- end
2740
-
2741
- let(:events) do
2742
- subscriber.command_started_events('delete')
2743
- end
2744
-
2745
- let(:collection) do
2746
- authorized_collection.with(write_concern: {w: 2})
2747
- end
2748
-
2749
- let!(:command) do
2750
- Utils.get_command_event(authorized_client, 'delete') do |client|
2751
- collection.delete_one(selector, session: session, write_concern: {w: 1},
2752
- bypass_document_validation: true)
2753
- end.command
2754
- end
2755
-
2756
- it 'deletes one successfully with correct options sent to server' do
2757
- expect(events.length).to eq(1)
2758
- expect(command[:writeConcern]).to_not be_nil
2759
- expect(command[:writeConcern][:w]).to eq(1)
2760
- expect(command[:bypassDocumentValidation]).to eq(true)
2761
- end
2762
- end
2763
- end
2764
-
2765
- describe '#delete_many' do
2766
-
2767
- before do
2768
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test2' }])
2769
- end
2770
-
2771
- context 'when a selector was provided' do
2772
-
2773
- let(:selector) do
2774
- { field: 'test1' }
2775
- end
2776
-
2777
- it 'deletes the matching documents in the collection' do
2778
- expect(authorized_collection.delete_many(selector).deleted_count).to eq(1)
2779
- end
2780
- end
2781
-
2782
- context 'when no selector was provided' do
2783
-
2784
- it 'deletes all the documents in the collection' do
2785
- expect(authorized_collection.delete_many.deleted_count).to eq(2)
2786
- end
2787
- end
2788
-
2789
- context 'when the deletes fail' do
2790
- require_topology :single
2791
-
2792
- let(:result) do
2793
- collection_invalid_write_concern.delete_many
2794
- end
2795
-
2796
- it 'raises an OperationFailure' do
2797
- expect {
2798
- result
2799
- }.to raise_exception(Mongo::Error::OperationFailure)
2800
- end
2801
- end
2802
-
2803
- context 'when a session is provided' do
2804
-
2805
- let(:session) do
2806
- authorized_client.start_session
2807
- end
2808
-
2809
- let(:operation) do
2810
- authorized_collection.delete_many({}, session: session)
2811
- end
2812
-
2813
- let(:failed_operation) do
2814
- authorized_collection.delete_many({ '$._id' => 1}, session: session)
2815
- end
2816
-
2817
- let(:client) do
2818
- authorized_client
2819
- end
2820
-
2821
- it_behaves_like 'an operation using a session'
2822
- it_behaves_like 'a failed operation using a session'
2823
- end
2824
-
2825
- context 'when unacknowledged writes are used with an explicit session' do
2826
-
2827
- let(:collection_with_unacknowledged_write_concern) do
2828
- authorized_collection.with(write: { w: 0 })
2829
- end
2830
-
2831
- let(:operation) do
2832
- collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1}, session: session)
2833
- end
2834
-
2835
- it_behaves_like 'an explicit session with an unacknowledged write'
2836
- end
2837
-
2838
- context 'when unacknowledged writes are used with an implicit session' do
2839
-
2840
- let(:collection_with_unacknowledged_write_concern) do
2841
- client.with(write: { w: 0 })[TEST_COLL]
2842
- end
2843
-
2844
- let(:operation) do
2845
- collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1 })
2846
- end
2847
-
2848
- it_behaves_like 'an implicit session with an unacknowledged write'
2849
- end
2850
-
2851
- context 'when a collation is specified' do
2852
-
2853
- let(:selector) do
2854
- { name: 'BANG' }
2855
- end
2856
-
2857
- let(:result) do
2858
- authorized_collection.delete_many(selector, options)
2859
- end
2860
-
2861
- before do
2862
- authorized_collection.insert_one(name: 'bang')
2863
- authorized_collection.insert_one(name: 'bang')
2864
- end
2865
-
2866
- let(:options) do
2867
- { collation: { locale: 'en_US', strength: 2 } }
2868
- end
2869
-
2870
- context 'when the server selected supports collations' do
2871
- min_server_fcv '3.4'
2872
-
2873
- it 'applies the collation' do
2874
- expect(result.written_count).to eq(2)
2875
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
2876
- end
2877
-
2878
- context 'when unacknowledged writes is used' do
2879
-
2880
- let(:collection_with_unacknowledged_write_concern) do
2881
- authorized_collection.with(write: { w: 0 })
2882
- end
2883
-
2884
- let(:result) do
2885
- collection_with_unacknowledged_write_concern.delete_many(selector, options)
2886
- end
2887
-
2888
- it 'raises an exception' do
2889
- expect {
2890
- result
2891
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2892
- end
2893
-
2894
- context 'when a String key is used' do
2895
-
2896
- let(:options) do
2897
- { 'collation' => { locale: 'en_US', strength: 2 } }
2898
- end
2899
-
2900
- it 'raises an exception' do
2901
- expect {
2902
- result
2903
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2904
- end
2905
- end
2906
- end
2907
- end
2908
-
2909
- context 'when the server selected does not support collations' do
2910
- max_server_version '3.2'
2911
-
2912
- it 'raises an exception' do
2913
- expect {
2914
- result
2915
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2916
- end
2917
-
2918
- context 'when a String key is used' do
2919
-
2920
- let(:options) do
2921
- { 'collation' => { locale: 'en_US', strength: 2 } }
2922
- end
2923
-
2924
- it 'raises an exception' do
2925
- expect {
2926
- result
2927
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
2928
- end
2929
- end
2930
- end
2931
- end
2932
-
2933
- context 'when a collation is not specified' do
2934
-
2935
- let(:selector) do
2936
- { name: 'BANG' }
2937
- end
2938
-
2939
- let(:result) do
2940
- authorized_collection.delete_many(selector)
2941
- end
2942
-
2943
- before do
2944
- authorized_collection.insert_one(name: 'bang')
2945
- authorized_collection.insert_one(name: 'bang')
2946
- end
2947
-
2948
- it 'does not apply the collation' do
2949
- expect(result.written_count).to eq(0)
2950
- expect(authorized_collection.find(name: 'bang').count).to eq(2)
2951
- end
2952
- end
2953
-
2954
- context 'when various options passed in' do
2955
- # w: 2 requires a replica set
2956
- require_topology :replica_set
2957
-
2958
- # https://jira.mongodb.org/browse/RUBY-2306
2959
- min_server_fcv '3.6'
2960
-
2961
- before do
2962
- collection.insert_many([{ name: 'test1' }, { name: 'test2' }, { name: 'test3'}])
2963
- end
2964
-
2965
- let(:selector) do
2966
- {name: 'test1'}
2967
- end
2968
-
2969
- let(:session) do
2970
- authorized_client.start_session
2971
- end
2972
-
2973
- let(:events) do
2974
- subscriber.command_started_events('delete')
2975
- end
2976
-
2977
- let(:collection) do
2978
- authorized_collection.with(write_concern: {w: 1})
2979
- end
2980
-
2981
- let!(:command) do
2982
- Utils.get_command_event(authorized_client, 'delete') do |client|
2983
- collection.delete_many(selector, session: session, write_concern: {w: 2},
2984
- bypass_document_validation: true)
2985
- end.command
2986
- end
2987
-
2988
- it 'deletes many successfully with correct options sent to server' do
2989
- expect(events.length).to eq(1)
2990
- expect(command[:writeConcern]).to_not be_nil
2991
- expect(command[:writeConcern][:w]).to eq(2)
2992
- expect(command[:bypassDocumentValidation]).to be(true)
2993
- end
2994
- end
2995
- end
2996
-
2997
- describe '#parallel_scan' do
2998
- max_server_version '4.0'
2999
- require_topology :single, :replica_set
3000
-
3001
- let(:documents) do
3002
- (1..200).map do |i|
3003
- { name: "testing-scan-#{i}" }
3004
- end
3005
- end
3006
-
3007
- before do
3008
- authorized_collection.insert_many(documents)
3009
- end
3010
-
3011
- let(:cursors) do
3012
- authorized_collection.parallel_scan(2)
3013
- end
3014
-
3015
- it 'returns an array of cursors' do
3016
- cursors.each do |cursor|
3017
- expect(cursor.class).to be(Mongo::Cursor)
3018
- end
3019
- end
3020
-
3021
- it 'returns the correct number of documents' do
3022
- expect(
3023
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
3024
- ).to eq(200)
3025
- end
3026
-
3027
- context 'when a session is provided' do
3028
- require_wired_tiger
3029
-
3030
- let(:cursors) do
3031
- authorized_collection.parallel_scan(2, session: session)
3032
- end
3033
-
3034
- let(:operation) do
3035
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
3036
- end
3037
-
3038
- let(:failed_operation) do
3039
- authorized_collection.parallel_scan(-2, session: session)
3040
- end
3041
-
3042
- let(:client) do
3043
- authorized_client
3044
- end
3045
-
3046
- it_behaves_like 'an operation using a session'
3047
- it_behaves_like 'a failed operation using a session'
3048
- end
3049
-
3050
- context 'when a session is not provided' do
3051
- let(:collection) { client['test'] }
3052
-
3053
- let(:cursors) do
3054
- collection.parallel_scan(2)
3055
- end
3056
-
3057
- let(:operation) do
3058
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
3059
- end
3060
-
3061
- let(:failed_operation) do
3062
- collection.parallel_scan(-2)
3063
- end
3064
-
3065
- let(:command) do
3066
- operation
3067
- event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
3068
- expect(event).not_to be_nil
3069
- event.command
3070
- end
3071
-
3072
- it_behaves_like 'an operation not using a session'
3073
- it_behaves_like 'a failed operation not using a session'
3074
- end
3075
-
3076
- context 'when a session supporting causal consistency is used' do
3077
- require_wired_tiger
3078
-
3079
- let(:cursors) do
3080
- collection.parallel_scan(2, session: session)
3081
- end
3082
-
3083
- let(:operation) do
3084
- cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
3085
- end
3086
-
3087
- let(:command) do
3088
- operation
3089
- event = subscriber.started_events.find { |cmd| cmd.command_name == 'parallelCollectionScan' }
3090
- expect(event).not_to be_nil
3091
- event.command
3092
- end
3093
-
3094
- it_behaves_like 'an operation supporting causally consistent reads'
3095
- end
3096
-
3097
- context 'when a read concern is provided' do
3098
- require_wired_tiger
3099
- min_server_fcv '3.2'
3100
-
3101
- let(:result) do
3102
- authorized_collection.with(options).parallel_scan(2)
3103
- end
3104
-
3105
- context 'when the read concern is valid' do
3106
-
3107
- let(:options) do
3108
- { read_concern: { level: 'local' }}
3109
- end
3110
-
3111
- it 'sends the read concern' do
3112
- expect { result }.to_not raise_error
3113
- end
3114
- end
3115
-
3116
- context 'when the read concern is not valid' do
3117
-
3118
- let(:options) do
3119
- { read_concern: { level: 'idontknow' }}
3120
- end
3121
-
3122
- it 'raises an exception' do
3123
- expect {
3124
- result
3125
- }.to raise_error(Mongo::Error::OperationFailure)
3126
- end
3127
- end
3128
- end
3129
-
3130
- context 'when the collection has a read preference' do
3131
- require_topology :single, :replica_set
3132
-
3133
- before do
3134
- allow(collection.client.cluster).to receive(:single?).and_return(false)
3135
- end
3136
-
3137
- let(:client) do
3138
- authorized_client.with(server_selection_timeout: 0.2)
3139
- end
3140
-
3141
- let(:collection) do
3142
- client[authorized_collection.name,
3143
- read: { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }]
3144
- end
3145
-
3146
- let(:result) do
3147
- collection.parallel_scan(2)
3148
- end
3149
-
3150
- it 'uses that read preference' do
3151
- expect {
3152
- result
3153
- }.to raise_exception(Mongo::Error::NoServerAvailable)
3154
- end
3155
- end
3156
-
3157
- context 'when a max time ms value is provided' do
3158
- require_topology :single, :replica_set
3159
-
3160
- let(:result) do
3161
- authorized_collection.parallel_scan(2, options)
3162
- end
3163
-
3164
- context 'when the read concern is valid' do
3165
-
3166
- let(:options) do
3167
- { max_time_ms: 5 }
3168
- end
3169
-
3170
- it 'sends the max time ms value' do
3171
- expect { result }.to_not raise_error
3172
- end
3173
- end
3174
-
3175
- context 'when the max time ms is not valid' do
3176
-
3177
- let(:options) do
3178
- { max_time_ms: 0.1 }
3179
- end
3180
-
3181
- it 'raises an exception' do
3182
- expect {
3183
- result
3184
- }.to raise_error(Mongo::Error::OperationFailure)
3185
- end
3186
- end
3187
- end
3188
- end
3189
-
3190
- describe '#replace_one' do
3191
-
3192
- let(:selector) do
3193
- { field: 'test1' }
3194
- end
3195
-
3196
- context 'when a selector was provided' do
3197
-
3198
- before do
3199
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
3200
- end
3201
-
3202
- let!(:response) do
3203
- authorized_collection.replace_one(selector, { field: 'testing' })
3204
- end
3205
-
3206
- let(:updated) do
3207
- authorized_collection.find(field: 'testing').first
3208
- end
3209
-
3210
- it 'updates the first matching document in the collection' do
3211
- expect(response.modified_count).to eq(1)
3212
- end
3213
-
3214
- it 'updates the documents in the collection' do
3215
- expect(updated[:field]).to eq('testing')
3216
- end
3217
- end
3218
-
3219
- context 'when upsert is false' do
3220
-
3221
- let!(:response) do
3222
- authorized_collection.replace_one(selector, { field: 'test1' }, upsert: false)
3223
- end
3224
-
3225
- let(:updated) do
3226
- authorized_collection.find(field: 'test1').to_a
3227
- end
3228
-
3229
- it 'reports that no documents were written' do
3230
- expect(response.modified_count).to eq(0)
3231
- end
3232
-
3233
- it 'does not insert the document' do
3234
- expect(updated).to be_empty
3235
- end
3236
- end
3237
-
3238
- context 'when upsert is true' do
3239
-
3240
- let!(:response) do
3241
- authorized_collection.replace_one(selector, { field: 'test1' }, upsert: true)
3242
- end
3243
-
3244
- let(:updated) do
3245
- authorized_collection.find(field: 'test1').first
3246
- end
3247
-
3248
- it 'reports that a document was written' do
3249
- expect(response.written_count).to eq(1)
3250
- end
3251
-
3252
- it 'inserts the document' do
3253
- expect(updated[:field]).to eq('test1')
3254
- end
3255
- end
3256
-
3257
- context 'when upsert is not specified' do
3258
-
3259
- let!(:response) do
3260
- authorized_collection.replace_one(selector, { field: 'test1' })
3261
- end
3262
-
3263
- let(:updated) do
3264
- authorized_collection.find(field: 'test1').to_a
3265
- end
3266
-
3267
- it 'reports that no documents were written' do
3268
- expect(response.modified_count).to eq(0)
3269
- end
3270
-
3271
- it 'does not insert the document' do
3272
- expect(updated).to be_empty
3273
- end
3274
- end
3275
-
3276
- context 'when the replace fails' do
3277
-
3278
- let(:result) do
3279
- authorized_collection.replace_one(selector, { '$s' => 'test1' })
3280
- end
3281
-
3282
- it 'raises an OperationFailure' do
3283
- expect {
3284
- result
3285
- }.to raise_exception(Mongo::Error::OperationFailure)
3286
- end
3287
- end
3288
-
3289
- context 'when collection has a validator' do
3290
- min_server_fcv '3.2'
3291
-
3292
- around(:each) do |spec|
3293
- authorized_client[:validating,
3294
- :validator => { :a => { '$exists' => true } }].tap do |c|
3295
- c.create
3296
- end
3297
- spec.run
3298
- collection_with_validator.drop
3299
- end
3300
-
3301
- before do
3302
- collection_with_validator.insert_one({ a: 1 })
3303
- end
3304
-
3305
- context 'when the document is valid' do
3306
-
3307
- let(:result) do
3308
- collection_with_validator.replace_one({ a: 1 }, { a: 5 })
3309
- end
3310
-
3311
- it 'replaces successfully' do
3312
- expect(result.modified_count).to eq(1)
3313
- end
3314
- end
3315
-
3316
- context 'when the document is invalid' do
3317
-
3318
- context 'when bypass_document_validation is not set' do
3319
-
3320
- let(:result2) do
3321
- collection_with_validator.replace_one({ a: 1 }, { x: 5 })
3322
- end
3323
-
3324
- it 'raises OperationFailure' do
3325
- expect {
3326
- result2
3327
- }.to raise_exception(Mongo::Error::OperationFailure)
3328
- end
3329
- end
3330
-
3331
- context 'when bypass_document_validation is true' do
3332
-
3333
- let(:result3) do
3334
- collection_with_validator.replace_one(
3335
- { a: 1 }, { x: 1 }, :bypass_document_validation => true)
3336
- end
3337
-
3338
- it 'replaces successfully' do
3339
- expect(result3.written_count).to eq(1)
3340
- end
3341
- end
3342
- end
3343
- end
3344
-
3345
- context 'when a collation is specified' do
3346
-
3347
- let(:selector) do
3348
- { name: 'BANG' }
3349
- end
3350
-
3351
- let(:result) do
3352
- authorized_collection.replace_one(selector, { name: 'doink' }, options)
3353
- end
3354
-
3355
- before do
3356
- authorized_collection.insert_one(name: 'bang')
3357
- end
3358
-
3359
- let(:options) do
3360
- { collation: { locale: 'en_US', strength: 2 } }
3361
- end
3362
-
3363
- context 'when the server selected supports collations' do
3364
- min_server_fcv '3.4'
3365
-
3366
- it 'applies the collation' do
3367
- expect(result.written_count).to eq(1)
3368
- expect(authorized_collection.find(name: 'doink').count).to eq(1)
3369
- end
3370
-
3371
- context 'when unacknowledged writes is used' do
3372
-
3373
- let(:collection_with_unacknowledged_write_concern) do
3374
- authorized_collection.with(write: { w: 0 })
3375
- end
3376
-
3377
- let(:result) do
3378
- collection_with_unacknowledged_write_concern.replace_one(selector, { name: 'doink' }, options)
3379
- end
3380
-
3381
- it 'raises an exception' do
3382
- expect {
3383
- result
3384
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3385
- end
3386
-
3387
- context 'when a String key is used' do
3388
-
3389
- let(:options) do
3390
- { 'collation' => { locale: 'en_US', strength: 2 } }
3391
- end
3392
-
3393
- it 'raises an exception' do
3394
- expect {
3395
- result
3396
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3397
- end
3398
- end
3399
- end
3400
- end
3401
-
3402
- context 'when the server selected does not support collations' do
3403
- max_server_version '3.2'
3404
-
3405
- it 'raises an exception' do
3406
- expect {
3407
- result
3408
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3409
- end
3410
-
3411
- context 'when a String key is used' do
3412
-
3413
- let(:options) do
3414
- { 'collation' => { locale: 'en_US', strength: 2 } }
3415
- end
3416
-
3417
- it 'raises an exception' do
3418
- expect {
3419
- result
3420
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3421
- end
3422
- end
3423
- end
3424
- end
3425
-
3426
- context 'when a collation is not specified' do
3427
-
3428
- let(:selector) do
3429
- { name: 'BANG' }
3430
- end
3431
-
3432
- let(:result) do
3433
- authorized_collection.replace_one(selector, { name: 'doink' })
3434
- end
3435
-
3436
- before do
3437
- authorized_collection.insert_one(name: 'bang')
3438
- end
3439
-
3440
- it 'does not apply the collation' do
3441
- expect(result.written_count).to eq(0)
3442
- expect(authorized_collection.find(name: 'bang').count).to eq(1)
3443
- end
3444
- end
3445
-
3446
- context 'when a session is provided' do
3447
-
3448
- let(:selector) do
3449
- { name: 'BANG' }
3450
- end
3451
-
3452
- before do
3453
- authorized_collection.insert_one(name: 'bang')
3454
- end
3455
-
3456
- let(:session) do
3457
- authorized_client.start_session
3458
- end
3459
-
3460
- let(:operation) do
3461
- authorized_collection.replace_one(selector, { name: 'doink' }, session: session)
3462
- end
3463
-
3464
- let(:failed_operation) do
3465
- authorized_collection.replace_one({ '$._id' => 1 }, { name: 'doink' }, session: session)
3466
- end
3467
-
3468
- let(:client) do
3469
- authorized_client
3470
- end
3471
-
3472
- it_behaves_like 'an operation using a session'
3473
- it_behaves_like 'a failed operation using a session'
3474
- end
3475
-
3476
- context 'when unacknowledged writes is used with an explicit session' do
3477
-
3478
- let(:collection_with_unacknowledged_write_concern) do
3479
- authorized_collection.with(write: { w: 0 })
3480
- end
3481
-
3482
- let(:operation) do
3483
- collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 }, session: session)
3484
- end
3485
-
3486
- it_behaves_like 'an explicit session with an unacknowledged write'
3487
- end
3488
-
3489
- context 'when unacknowledged writes is used with an implicit session' do
3490
-
3491
- let(:collection_with_unacknowledged_write_concern) do
3492
- client.with(write: { w: 0 })[TEST_COLL]
3493
- end
3494
-
3495
- let(:operation) do
3496
- collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 })
3497
- end
3498
-
3499
- it_behaves_like 'an implicit session with an unacknowledged write'
3500
- end
3501
-
3502
- context 'when various options passed in' do
3503
- # w: 2 requires a replica set
3504
- require_topology :replica_set
3505
-
3506
- # https://jira.mongodb.org/browse/RUBY-2306
3507
- min_server_fcv '3.6'
3508
-
3509
- before do
3510
- authorized_collection.insert_one({field: 'test1'})
3511
- end
3512
-
3513
- let(:session) do
3514
- authorized_client.start_session
3515
- end
3516
-
3517
- let(:events) do
3518
- subscriber.command_started_events('update')
3519
- end
3520
-
3521
- let(:collection) do
3522
- authorized_collection.with(write_concern: {w: 3})
3523
- end
3524
-
3525
- let(:updated) do
3526
- collection.find(field: 'test4').first
3527
- end
3528
-
3529
- let!(:command) do
3530
- Utils.get_command_event(authorized_client, 'update') do |client|
3531
- collection.replace_one(selector, { field: 'test4'},
3532
- session: session, :return_document => :after, write_concern: {w: 2},
3533
- upsert: true, bypass_document_validation: true)
3534
- end.command
3535
- end
3536
-
3537
- it 'replaced one successfully with correct options sent to server' do
3538
- expect(updated[:field]).to eq('test4')
3539
- expect(events.length).to eq(1)
3540
- expect(command[:writeConcern]).to_not be_nil
3541
- expect(command[:writeConcern][:w]).to eq(2)
3542
- expect(command[:bypassDocumentValidation]).to be(true)
3543
- expect(command[:updates][0][:upsert]).to be(true)
3544
- end
3545
- end
3546
- end
3547
-
3548
- describe '#update_many' do
3549
-
3550
- let(:selector) do
3551
- { field: 'test' }
3552
- end
3553
-
3554
- context 'when a selector was provided' do
3555
-
3556
- before do
3557
- authorized_collection.insert_many([{ field: 'test' }, { field: 'test' }])
3558
- end
3559
-
3560
- let!(:response) do
3561
- authorized_collection.update_many(selector, '$set'=> { field: 'testing' })
3562
- end
3563
-
3564
- let(:updated) do
3565
- authorized_collection.find(field: 'testing').to_a.last
3566
- end
3567
-
3568
- it 'returns the number updated' do
3569
- expect(response.modified_count).to eq(2)
3570
- end
3571
-
3572
- it 'updates the documents in the collection' do
3573
- expect(updated[:field]).to eq('testing')
3574
- end
3575
- end
3576
-
3577
- context 'when upsert is false' do
3578
-
3579
- let(:response) do
3580
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
3581
- upsert: false)
3582
- end
3583
-
3584
- let(:updated) do
3585
- authorized_collection.find.to_a
3586
- end
3587
-
3588
- it 'reports that no documents were updated' do
3589
- expect(response.modified_count).to eq(0)
3590
- end
3591
-
3592
- it 'updates no documents in the collection' do
3593
- expect(updated).to be_empty
3594
- end
3595
- end
3596
-
3597
- context 'when upsert is true' do
3598
-
3599
- let!(:response) do
3600
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } },
3601
- upsert: true)
3602
- end
3603
-
3604
- let(:updated) do
3605
- authorized_collection.find.to_a.last
3606
- end
3607
-
3608
- it 'reports that a document was written' do
3609
- expect(response.written_count).to eq(1)
3610
- end
3611
-
3612
- it 'inserts a document into the collection' do
3613
- expect(updated[:field]).to eq('testing')
3614
- end
3615
- end
3616
-
3617
- context 'when upsert is not specified' do
3618
-
3619
- let(:response) do
3620
- authorized_collection.update_many(selector, { '$set'=> { field: 'testing' } })
3621
- end
3622
-
3623
- let(:updated) do
3624
- authorized_collection.find.to_a
3625
- end
3626
-
3627
- it 'reports that no documents were updated' do
3628
- expect(response.modified_count).to eq(0)
3629
- end
3630
-
3631
- it 'updates no documents in the collection' do
3632
- expect(updated).to be_empty
3633
- end
3634
- end
3635
-
3636
- context 'when arrayFilters is provided' do
3637
-
3638
- let(:selector) do
3639
- { '$or' => [{ _id: 0 }, { _id: 1 }]}
3640
- end
3641
-
3642
- context 'when the server supports arrayFilters' do
3643
- min_server_fcv '3.6'
3644
-
3645
- before do
3646
- authorized_collection.insert_many([{
3647
- _id: 0, x: [
3648
- { y: 1 },
3649
- { y: 2 },
3650
- { y: 3 }
3651
- ]
3652
- },
3653
- {
3654
- _id: 1,
3655
- x: [
3656
- { y: 3 },
3657
- { y: 2 },
3658
- { y: 1 }
3659
- ]
3660
- }])
3661
- end
3662
-
3663
- let(:result) do
3664
- authorized_collection.update_many(selector,
3665
- { '$set' => { 'x.$[i].y' => 5 } },
3666
- options)
3667
- end
3668
-
3669
- context 'when a Symbol key is used' do
3670
-
3671
- let(:options) do
3672
- { array_filters: [{ 'i.y' => 3 }] }
3673
- end
3674
-
3675
- it 'applies the arrayFilters' do
3676
- expect(result.matched_count).to eq(2)
3677
- expect(result.modified_count).to eq(2)
3678
-
3679
- docs = authorized_collection.find(selector, sort: { _id: 1 }).to_a
3680
- expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
3681
- expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
3682
- end
3683
- end
3684
-
3685
- context 'when a String key is used' do
3686
- let(:options) do
3687
- { 'array_filters' => [{ 'i.y' => 3 }] }
3688
- end
3689
-
3690
- it 'applies the arrayFilters' do
3691
- expect(result.matched_count).to eq(2)
3692
- expect(result.modified_count).to eq(2)
3693
-
3694
- docs = authorized_collection.find({}, sort: { _id: 1 }).to_a
3695
- expect(docs[0]['x']).to eq ([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 5 }])
3696
- expect(docs[1]['x']).to eq ([{ 'y' => 5 }, { 'y' => 2 }, { 'y' => 1 }])
3697
- end
3698
- end
3699
- end
3700
-
3701
- context 'when the server does not support arrayFilters' do
3702
- max_server_version '3.4'
3703
-
3704
- let(:result) do
3705
- authorized_collection.update_many(selector,
3706
- { '$set' => { 'x.$[i].y' => 5 } },
3707
- options)
3708
- end
3709
-
3710
- context 'when a Symbol key is used' do
3711
-
3712
- let(:options) do
3713
- { array_filters: [{ 'i.y' => 3 }] }
3714
- end
3715
-
3716
- it 'raises an exception' do
3717
- expect {
3718
- result
3719
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3720
- end
3721
- end
3722
-
3723
- context 'when a String key is used' do
3724
-
3725
- let(:options) do
3726
- { 'array_filters' => [{ 'i.y' => 3 }] }
3727
- end
3728
-
3729
- it 'raises an exception' do
3730
- expect {
3731
- result
3732
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
3733
- end
3734
- end
3735
- end
3736
- end
3737
-
3738
- context 'when the updates fail' do
3739
-
3740
- let(:result) do
3741
- authorized_collection.update_many(selector, { '$s'=> { field: 'testing' } })
3742
- end
3743
-
3744
- it 'raises an OperationFailure' do
3745
- expect {
3746
- result
3747
- }.to raise_exception(Mongo::Error::OperationFailure)
3748
- end
3749
- end
3750
-
3751
- context 'when collection has a validator' do
3752
- min_server_fcv '3.2'
3753
-
3754
- around(:each) do |spec|
3755
- authorized_client[:validating,
3756
- :validator => { :a => { '$exists' => true } }].tap do |c|
3757
- c.create
3758
- end
3759
- spec.run
3760
- collection_with_validator.drop
3761
- end
3762
-
3763
- before do
3764
- collection_with_validator.insert_many([{ a: 1 }, { a: 2 }])
3765
- end
3766
-
3767
- context 'when the document is valid' do
3768
-
3769
- let(:result) do
3770
- collection_with_validator.update_many(
3771
- { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
3772
- end
3773
-
3774
- it 'updates successfully' do
3775
- expect(result.modified_count).to eq(2)
3776
- end
3777
- end
3778
-
3779
- context 'when the document is invalid' do
3780
-
3781
- context 'when bypass_document_validation is not set' do
3782
-
3783
- let(:result2) do
3784
- collection_with_validator.update_many(
3785
- { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
3786
- end
3787
-
3788
- it 'raises OperationFailure' do
3789
- expect {
3790
- result2
3791
- }.to raise_exception(Mongo::Error::OperationFailure)
3792
- end
3793
- end
3794
-
3795
- context 'when bypass_document_validation is true' do
3796
-
3797
- let(:result3) do
3798
- collection_with_validator.update_many(
3799
- { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
3800
- :bypass_document_validation => true)
3801
- end
3802
-
3803
- it 'updates successfully' do
3804
- expect(result3.written_count).to eq(2)
3805
- end
3806
- end
3807
- end
3808
- end
3809
-
3810
- context 'when a collation is specified' do
3811
-
3812
- let(:selector) do
3813
- { name: 'BANG' }
3814
- end
3815
-
3816
- let(:result) do
3817
- authorized_collection.update_many(selector, { '$set' => { other: 'doink' } }, options)
3818
- end
3819
-
3820
- before do
3821
- authorized_collection.insert_one(name: 'bang')
3822
- authorized_collection.insert_one(name: 'baNG')
3823
- end
3824
-
3825
- let(:options) do
3826
- { collation: { locale: 'en_US', strength: 2 } }
3827
- end
3828
-
3829
- context 'when the server selected supports collations' do
3830
- min_server_fcv '3.4'
3831
-
3832
- it 'applies the collation' do
3833
- expect(result.written_count).to eq(2)
3834
- expect(authorized_collection.find(other: 'doink').count).to eq(2)
3835
- end
3836
-
3837
- context 'when unacknowledged writes is used' do
3838
-
3839
- let(:collection_with_unacknowledged_write_concern) do
3840
- authorized_collection.with(write: { w: 0 })
3841
- end
3842
-
3843
- let(:result) do
3844
- collection_with_unacknowledged_write_concern.update_many(selector, { '$set' => { other: 'doink' } }, options)
3845
- end
3846
-
3847
- it 'raises an exception' do
3848
- expect {
3849
- result
3850
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3851
- end
3852
-
3853
- context 'when a String key is used' do
3854
-
3855
- let(:options) do
3856
- { 'collation' => { locale: 'en_US', strength: 2 } }
3857
- end
3858
-
3859
- it 'raises an exception' do
3860
- expect {
3861
- result
3862
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3863
- end
3864
- end
3865
- end
3866
- end
3867
-
3868
- context 'when the server selected does not support collations' do
3869
- max_server_version '3.2'
3870
-
3871
- it 'raises an exception' do
3872
- expect {
3873
- result
3874
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3875
- end
3876
-
3877
- context 'when a String key is used' do
3878
-
3879
- let(:options) do
3880
- { 'collation' => { locale: 'en_US', strength: 2 } }
3881
- end
3882
-
3883
- it 'raises an exception' do
3884
- expect {
3885
- result
3886
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
3887
- end
3888
- end
3889
- end
3890
- end
3891
-
3892
- context 'when collation is not specified' do
3893
-
3894
- let(:selector) do
3895
- {name: 'BANG'}
3896
- end
3897
-
3898
- let(:result) do
3899
- authorized_collection.update_many(selector, { '$set' => {other: 'doink'} })
3900
- end
3901
-
3902
- before do
3903
- authorized_collection.insert_one(name: 'bang')
3904
- authorized_collection.insert_one(name: 'baNG')
3905
- end
3906
-
3907
- it 'does not apply the collation' do
3908
- expect(result.written_count).to eq(0)
3909
- end
3910
- end
3911
-
3912
- context 'when a session is provided' do
3913
-
3914
- let(:selector) do
3915
- { name: 'BANG' }
3916
- end
3917
-
3918
- let(:operation) do
3919
- authorized_collection.update_many(selector, { '$set' => {other: 'doink'} }, session: session)
3920
- end
3921
-
3922
- before do
3923
- authorized_collection.insert_one(name: 'bang')
3924
- authorized_collection.insert_one(name: 'baNG')
3925
- end
3926
-
3927
- let(:session) do
3928
- authorized_client.start_session
3929
- end
3930
-
3931
- let(:failed_operation) do
3932
- authorized_collection.update_many({ '$._id' => 1 }, { '$set' => {other: 'doink'} }, session: session)
3933
- end
3934
-
3935
- let(:client) do
3936
- authorized_client
3937
- end
3938
-
3939
- it_behaves_like 'an operation using a session'
3940
- it_behaves_like 'a failed operation using a session'
3941
- end
3942
-
3943
- context 'when unacknowledged writes is used with an explicit session' do
3944
-
3945
- let(:collection_with_unacknowledged_write_concern) do
3946
- authorized_collection.with(write: { w: 0 })
3947
- end
3948
-
3949
- let(:operation) do
3950
- collection_with_unacknowledged_write_concern.update_many({a: 1}, { '$set' => {x: 1} }, session: session)
3951
- end
3952
-
3953
- it_behaves_like 'an explicit session with an unacknowledged write'
3954
- end
3955
-
3956
- context 'when unacknowledged writes is used with an implicit session' do
3957
-
3958
- let(:collection_with_unacknowledged_write_concern) do
3959
- client.with(write: { w: 0 })[TEST_COLL]
3960
- end
3961
-
3962
- let(:operation) do
3963
- collection_with_unacknowledged_write_concern.update_many({a: 1}, {'$set' => {x: 1}})
3964
- end
3965
-
3966
- it_behaves_like 'an implicit session with an unacknowledged write'
3967
- end
3968
-
3969
- context 'when various options passed in' do
3970
- # w: 2 requires a replica set
3971
- require_topology :replica_set
3972
-
3973
- # https://jira.mongodb.org/browse/RUBY-2306
3974
- min_server_fcv '3.6'
3975
-
3976
- before do
3977
- collection.insert_many([{ field: 'test' }, { field: 'test2' }], session: session)
3978
- end
3979
-
3980
- let(:session) do
3981
- authorized_client.start_session
3982
- end
3983
-
3984
- let(:collection) do
3985
- authorized_collection.with(write_concern: {w: 1})
3986
- end
3987
-
3988
- let(:events) do
3989
- subscriber.command_started_events('update')
3990
- end
3991
-
3992
- let!(:command) do
3993
- Utils.get_command_event(authorized_client, 'update') do |client|
3994
- collection.update_many(selector, {'$set'=> { field: 'testing' }}, session: session,
3995
- write_concern: {w: 2}, bypass_document_validation: true, upsert: true)
3996
- end.command
3997
- end
3998
-
3999
- it 'updates many successfully with correct options sent to server' do
4000
- expect(events.length).to eq(1)
4001
- expect(collection.options[:write_concern]).to eq(w: 1)
4002
- expect(command[:writeConcern][:w]).to eq(2)
4003
- expect(command[:bypassDocumentValidation]).to be(true)
4004
- expect(command[:updates][0][:upsert]).to be(true)
4005
- end
4006
- end
4007
- end
4008
-
4009
- describe '#update_one' do
4010
-
4011
- let(:selector) do
4012
- { field: 'test1' }
4013
- end
4014
-
4015
- context 'when a selector was provided' do
4016
-
4017
- before do
4018
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
4019
- end
4020
-
4021
- let!(:response) do
4022
- authorized_collection.update_one(selector, '$set'=> { field: 'testing' })
4023
- end
4024
-
4025
- let(:updated) do
4026
- authorized_collection.find(field: 'testing').first
4027
- end
4028
-
4029
- it 'updates the first matching document in the collection' do
4030
- expect(response.modified_count).to eq(1)
4031
- end
4032
-
4033
- it 'updates the documents in the collection' do
4034
- expect(updated[:field]).to eq('testing')
4035
- end
4036
- end
4037
-
4038
- context 'when upsert is false' do
4039
-
4040
- let(:response) do
4041
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
4042
- upsert: false)
4043
- end
4044
-
4045
- let(:updated) do
4046
- authorized_collection.find.to_a
4047
- end
4048
-
4049
- it 'reports that no documents were updated' do
4050
- expect(response.modified_count).to eq(0)
4051
- end
4052
-
4053
- it 'updates no documents in the collection' do
4054
- expect(updated).to be_empty
4055
- end
4056
- end
4057
-
4058
- context 'when upsert is true' do
4059
-
4060
- let!(:response) do
4061
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } },
4062
- upsert: true)
4063
- end
4064
-
4065
- let(:updated) do
4066
- authorized_collection.find.first
4067
- end
4068
-
4069
- it 'reports that a document was written' do
4070
- expect(response.written_count).to eq(1)
4071
- end
4072
-
4073
- it 'inserts a document into the collection' do
4074
- expect(updated[:field]).to eq('testing')
4075
- end
4076
- end
4077
-
4078
- context 'when upsert is not specified' do
4079
-
4080
- let(:response) do
4081
- authorized_collection.update_one(selector, { '$set'=> { field: 'testing' } })
4082
- end
4083
-
4084
- let(:updated) do
4085
- authorized_collection.find.to_a
4086
- end
4087
-
4088
- it 'reports that no documents were updated' do
4089
- expect(response.modified_count).to eq(0)
4090
- end
4091
-
4092
- it 'updates no documents in the collection' do
4093
- expect(updated).to be_empty
4094
- end
4095
- end
4096
-
4097
- context 'when the update fails' do
4098
-
4099
- let(:result) do
4100
- authorized_collection.update_one(selector, { '$s'=> { field: 'testing' } })
4101
- end
4102
-
4103
- it 'raises an OperationFailure' do
4104
- expect {
4105
- result
4106
- }.to raise_exception(Mongo::Error::OperationFailure)
4107
- end
4108
- end
4109
-
4110
- context 'when collection has a validator' do
4111
- min_server_fcv '3.2'
4112
-
4113
- around(:each) do |spec|
4114
- authorized_client[:validating,
4115
- :validator => { :a => { '$exists' => true } }].tap do |c|
4116
- c.create
4117
- end
4118
- spec.run
4119
- collection_with_validator.drop
4120
- end
4121
-
4122
- before do
4123
- collection_with_validator.insert_one({ a: 1 })
4124
- end
4125
-
4126
- context 'when the document is valid' do
4127
-
4128
- let(:result) do
4129
- collection_with_validator.update_one(
4130
- { :a => { '$gt' => 0 } }, '$inc' => { :a => 1 } )
4131
- end
4132
-
4133
- it 'updates successfully' do
4134
- expect(result.modified_count).to eq(1)
4135
- end
4136
- end
4137
-
4138
- context 'when the document is invalid' do
4139
-
4140
- context 'when bypass_document_validation is not set' do
4141
-
4142
- let(:result2) do
4143
- collection_with_validator.update_one(
4144
- { :a => { '$gt' => 0 } }, '$unset' => { :a => '' })
4145
- end
4146
-
4147
- it 'raises OperationFailure' do
4148
- expect {
4149
- result2
4150
- }.to raise_exception(Mongo::Error::OperationFailure)
4151
- end
4152
- end
4153
-
4154
- context 'when bypass_document_validation is true' do
4155
-
4156
- let(:result3) do
4157
- collection_with_validator.update_one(
4158
- { :a => { '$gt' => 0 } }, { '$unset' => { :a => '' } },
4159
- :bypass_document_validation => true)
4160
- end
4161
-
4162
- it 'updates successfully' do
4163
- expect(result3.written_count).to eq(1)
4164
- end
4165
- end
4166
- end
4167
- end
4168
-
4169
- context 'when there is a collation specified' do
4170
-
4171
- let(:selector) do
4172
- { name: 'BANG' }
4173
- end
4174
-
4175
- let(:result) do
4176
- authorized_collection.update_one(selector, { '$set' => { other: 'doink' } }, options)
4177
- end
4178
-
4179
- before do
4180
- authorized_collection.insert_one(name: 'bang')
4181
- end
4182
-
4183
- let(:options) do
4184
- { collation: { locale: 'en_US', strength: 2 } }
4185
- end
4186
-
4187
- context 'when the server selected supports collations' do
4188
- min_server_fcv '3.4'
4189
-
4190
- it 'applies the collation' do
4191
- expect(result.written_count).to eq(1)
4192
- expect(authorized_collection.find(other: 'doink').count).to eq(1)
4193
- end
4194
-
4195
- context 'when unacknowledged writes is used' do
4196
-
4197
- let(:collection_with_unacknowledged_write_concern) do
4198
- authorized_collection.with(write: { w: 0 })
4199
- end
4200
-
4201
- let(:result) do
4202
- collection_with_unacknowledged_write_concern.update_one(selector, { '$set' => { other: 'doink' } }, options)
4203
- end
4204
-
4205
- it 'raises an exception' do
4206
- expect {
4207
- result
4208
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4209
- end
4210
-
4211
- context 'when a String key is used' do
4212
-
4213
- let(:options) do
4214
- { 'collation' => { locale: 'en_US', strength: 2 } }
4215
- end
4216
-
4217
- it 'raises an exception' do
4218
- expect {
4219
- result
4220
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4221
- end
4222
- end
4223
- end
4224
- end
4225
-
4226
- context 'when the server selected does not support collations' do
4227
- max_server_version '3.2'
4228
-
4229
- it 'raises an exception' do
4230
- expect {
4231
- result
4232
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4233
- end
4234
-
4235
- context 'when a String key is used' do
4236
-
4237
- let(:options) do
4238
- { 'collation' => { locale: 'en_US', strength: 2 } }
4239
- end
4240
-
4241
- it 'raises an exception' do
4242
- expect {
4243
- result
4244
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4245
- end
4246
- end
4247
- end
4248
- end
4249
-
4250
- context 'when a collation is not specified' do
4251
-
4252
- let(:selector) do
4253
- { name: 'BANG' }
4254
- end
4255
-
4256
- let(:result) do
4257
- authorized_collection.update_one(selector, { '$set' => { other: 'doink' } })
4258
- end
4259
-
4260
- before do
4261
- authorized_collection.insert_one(name: 'bang')
4262
- end
4263
-
4264
- it 'does not apply the collation' do
4265
- expect(result.written_count).to eq(0)
4266
- end
4267
- end
4268
-
4269
-
4270
- context 'when arrayFilters is provided' do
4271
-
4272
- let(:selector) do
4273
- { _id: 0}
4274
- end
4275
-
4276
- context 'when the server supports arrayFilters' do
4277
- min_server_fcv '3.6'
4278
-
4279
- before do
4280
- authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, {y: 3 }])
4281
- end
4282
-
4283
- let(:result) do
4284
- authorized_collection.update_one(selector,
4285
- { '$set' => { 'x.$[i].y' => 5 } },
4286
- options)
4287
- end
4288
-
4289
- context 'when a Symbol key is used' do
4290
-
4291
- let(:options) do
4292
- { array_filters: [{ 'i.y' => 3 }] }
4293
- end
4294
-
4295
- it 'applies the arrayFilters' do
4296
- expect(result.matched_count).to eq(1)
4297
- expect(result.modified_count).to eq(1)
4298
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
4299
- end
4300
- end
4301
-
4302
- context 'when a String key is used' do
4303
-
4304
- let(:options) do
4305
- { 'array_filters' => [{ 'i.y' => 3 }] }
4306
- end
4307
-
4308
- it 'applies the arrayFilters' do
4309
- expect(result.matched_count).to eq(1)
4310
- expect(result.modified_count).to eq(1)
4311
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
4312
- end
4313
- end
4314
- end
4315
-
4316
- context 'when the server does not support arrayFilters' do
4317
- max_server_version '3.4'
4318
-
4319
- let(:result) do
4320
- authorized_collection.update_one(selector,
4321
- { '$set' => { 'x.$[i].y' => 5 } },
4322
- options)
4323
- end
4324
-
4325
- context 'when a Symbol key is used' do
4326
-
4327
- let(:options) do
4328
- { array_filters: [{ 'i.y' => 3 }] }
4329
- end
4330
-
4331
- it 'raises an exception' do
4332
- expect {
4333
- result
4334
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
4335
- end
4336
- end
4337
-
4338
- context 'when a String key is used' do
4339
-
4340
- let(:options) do
4341
- { 'array_filters' => [{ 'i.y' => 3 }] }
4342
- end
4343
-
4344
- it 'raises an exception' do
4345
- expect {
4346
- result
4347
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
4348
- end
4349
- end
4350
- end
4351
- end
4352
-
4353
- context 'when the documents are sent with OP_MSG' do
4354
- min_server_fcv '3.6'
4355
-
4356
- let(:documents) do
4357
- [{ '_id' => 1, 'name' => '1'*16777191 }, { '_id' => 'y' }]
4358
- end
4359
-
4360
- before do
4361
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
4362
- client[TEST_COLL].update_one({ a: 1 }, {'$set' => { 'name' => '1'*16777149 }})
4363
- end
4364
-
4365
- let(:update_events) do
4366
- subscriber.started_events.select { |e| e.command_name == 'update' }
4367
- end
4368
-
4369
- it 'sends the documents in one OP_MSG' do
4370
- expect(update_events.size).to eq(1)
4371
- end
4372
- end
4373
-
4374
- context 'when a session is provided' do
4375
-
4376
- before do
4377
- authorized_collection.insert_many([{ field: 'test1' }, { field: 'test1' }])
4378
- end
4379
-
4380
- let(:session) do
4381
- authorized_client.start_session
4382
- end
4383
-
4384
- let(:operation) do
4385
- authorized_collection.update_one({ field: 'test' }, { '$set'=> { field: 'testing' } }, session: session)
4386
- end
4387
-
4388
- let(:failed_operation) do
4389
- authorized_collection.update_one({ '$._id' => 1 }, { '$set'=> { field: 'testing' } }, session: session)
4390
- end
4391
-
4392
- let(:client) do
4393
- authorized_client
4394
- end
4395
-
4396
- it_behaves_like 'an operation using a session'
4397
- it_behaves_like 'a failed operation using a session'
4398
- end
4399
-
4400
- context 'when unacknowledged writes is used with an explicit session' do
4401
-
4402
- let(:collection_with_unacknowledged_write_concern) do
4403
- authorized_collection.with(write: { w: 0 })
4404
- end
4405
-
4406
- let(:operation) do
4407
- collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 } }, session: session)
4408
- end
4409
-
4410
- it_behaves_like 'an explicit session with an unacknowledged write'
4411
- end
4412
-
4413
- context 'when unacknowledged writes is used with an implicit session' do
4414
-
4415
- let(:collection_with_unacknowledged_write_concern) do
4416
- client.with(write: { w: 0 })[TEST_COLL]
4417
- end
4418
-
4419
- let(:operation) do
4420
- collection_with_unacknowledged_write_concern.update_one({ a: 1 }, { '$set' => { x: 1 }})
4421
- end
4422
-
4423
- it_behaves_like 'an implicit session with an unacknowledged write'
4424
- end
4425
-
4426
- context 'when various options passed in' do
4427
- # w: 2 requires a replica set
4428
- require_topology :replica_set
4429
-
4430
- # https://jira.mongodb.org/browse/RUBY-2306
4431
- min_server_fcv '3.6'
4432
-
4433
- before do
4434
- collection.insert_many([{ field: 'test1' }, { field: 'test2' }], session: session)
4435
- end
4436
-
4437
- let(:session) do
4438
- authorized_client.start_session
4439
- end
4440
-
4441
- let(:collection) do
4442
- authorized_collection.with(write_concern: {w: 1})
4443
- end
4444
-
4445
- let(:events) do
4446
- subscriber.command_started_events('update')
4447
- end
4448
-
4449
- let!(:command) do
4450
- Utils.get_command_event(authorized_client, 'update') do |client|
4451
- collection.update_one(selector, { '$set'=> { field: 'testing' } }, session: session,
4452
- write_concern: {w: 2}, bypass_document_validation: true, :return_document => :after,
4453
- upsert: true)
4454
- end.command
4455
- end
4456
-
4457
- it 'updates one successfully with correct options sent to server' do
4458
- expect(events.length).to eq(1)
4459
- expect(command[:writeConcern]).to_not be_nil
4460
- expect(command[:writeConcern][:w]).to eq(2)
4461
- expect(collection.options[:write_concern]).to eq(w:1)
4462
- expect(command[:bypassDocumentValidation]).to be(true)
4463
- expect(command[:updates][0][:upsert]).to be(true)
4464
- end
4465
- end
4466
- end
4467
-
4468
- describe '#find_one_and_delete' do
4469
-
4470
- before do
4471
- authorized_collection.insert_many([{ field: 'test1' }])
4472
- end
4473
-
4474
- let(:selector) do
4475
- { field: 'test1' }
4476
- end
4477
-
4478
- context 'when a matching document is found' do
4479
-
4480
- context 'when a session is provided' do
4481
-
4482
- let(:operation) do
4483
- authorized_collection.find_one_and_delete(selector, session: session)
4484
- end
4485
-
4486
- let(:failed_operation) do
4487
- authorized_collection.find_one_and_delete({ '$._id' => 1 }, session: session)
4488
- end
4489
-
4490
- let(:session) do
4491
- authorized_client.start_session
4492
- end
4493
-
4494
- let(:client) do
4495
- authorized_client
4496
- end
4497
-
4498
- it_behaves_like 'an operation using a session'
4499
- it_behaves_like 'a failed operation using a session'
4500
- end
4501
-
4502
- context 'when no options are provided' do
4503
-
4504
- let!(:document) do
4505
- authorized_collection.find_one_and_delete(selector)
4506
- end
4507
-
4508
- it 'deletes the document from the database' do
4509
- expect(authorized_collection.find.to_a).to be_empty
4510
- end
4511
-
4512
- it 'returns the document' do
4513
- expect(document['field']).to eq('test1')
4514
- end
4515
- end
4516
-
4517
- context 'when a projection is provided' do
4518
-
4519
- let!(:document) do
4520
- authorized_collection.find_one_and_delete(selector, projection: { _id: 1 })
4521
- end
4522
-
4523
- it 'deletes the document from the database' do
4524
- expect(authorized_collection.find.to_a).to be_empty
4525
- end
4526
-
4527
- it 'returns the document with limited fields' do
4528
- expect(document['field']).to be_nil
4529
- expect(document['_id']).to_not be_nil
4530
- end
4531
- end
4532
-
4533
- context 'when a sort is provided' do
4534
-
4535
- let!(:document) do
4536
- authorized_collection.find_one_and_delete(selector, sort: { field: 1 })
4537
- end
4538
-
4539
- it 'deletes the document from the database' do
4540
- expect(authorized_collection.find.to_a).to be_empty
4541
- end
4542
-
4543
- it 'returns the document with limited fields' do
4544
- expect(document['field']).to eq('test1')
4545
- end
4546
- end
4547
-
4548
- context 'when max_time_ms is provided' do
4549
-
4550
- it 'includes the max_time_ms value in the command' do
4551
- expect {
4552
- authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
4553
- }.to raise_error(Mongo::Error::OperationFailure)
4554
- end
4555
- end
4556
- end
4557
-
4558
- context 'when no matching document is found' do
4559
-
4560
- let(:selector) do
4561
- { field: 'test5' }
4562
- end
4563
-
4564
- let!(:document) do
4565
- authorized_collection.find_one_and_delete(selector)
4566
- end
4567
-
4568
- it 'returns nil' do
4569
- expect(document).to be_nil
4570
- end
4571
- end
4572
-
4573
- context 'when the operation fails' do
4574
-
4575
- let(:result) do
4576
- authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
4577
- end
4578
-
4579
- it 'raises an OperationFailure' do
4580
- expect {
4581
- result
4582
- }.to raise_exception(Mongo::Error::OperationFailure)
4583
- end
4584
- end
4585
-
4586
- context 'when write_concern is provided' do
4587
- min_server_fcv '3.2'
4588
- require_topology :single
4589
-
4590
- it 'uses the write concern' do
4591
- expect {
4592
- authorized_collection.find_one_and_delete(selector,
4593
- write_concern: { w: 2 })
4594
- }.to raise_error(Mongo::Error::OperationFailure)
4595
- end
4596
- end
4597
-
4598
- context 'when the collection has a write concern' do
4599
- min_server_fcv '3.2'
4600
- require_topology :single
4601
-
4602
- let(:collection) do
4603
- authorized_collection.with(write: { w: 2 })
4604
- end
4605
-
4606
- it 'uses the write concern' do
4607
- expect {
4608
- collection.find_one_and_delete(selector,
4609
- write_concern: { w: 2 })
4610
- }.to raise_error(Mongo::Error::OperationFailure)
4611
- end
4612
- end
4613
-
4614
- context 'when collation is specified' do
4615
-
4616
- let(:selector) do
4617
- { name: 'BANG' }
4618
- end
4619
-
4620
- let(:result) do
4621
- authorized_collection.find_one_and_delete(selector, options)
4622
- end
4623
-
4624
- before do
4625
- authorized_collection.insert_one(name: 'bang')
4626
- end
4627
-
4628
- let(:options) do
4629
- { collation: { locale: 'en_US', strength: 2 } }
4630
- end
4631
-
4632
- context 'when the server selected supports collations' do
4633
- min_server_fcv '3.4'
4634
-
4635
- it 'applies the collation' do
4636
- expect(result['name']).to eq('bang')
4637
- expect(authorized_collection.find(name: 'bang').count).to eq(0)
4638
- end
4639
- end
4640
-
4641
- context 'when the server selected does not support collations' do
4642
- max_server_version '3.2'
4643
-
4644
- it 'raises an exception' do
4645
- expect {
4646
- result
4647
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4648
- end
4649
-
4650
- context 'when a String key is used' do
4651
-
4652
- let(:options) do
4653
- { 'collation' => { locale: 'en_US', strength: 2 } }
4654
- end
4655
-
4656
- it 'raises an exception' do
4657
- expect {
4658
- result
4659
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
4660
- end
4661
- end
4662
- end
4663
- end
4664
-
4665
- context 'when collation is not specified' do
4666
-
4667
- let(:selector) do
4668
- { name: 'BANG' }
4669
- end
4670
-
4671
- let(:result) do
4672
- authorized_collection.find_one_and_delete(selector)
4673
- end
4674
-
4675
- before do
4676
- authorized_collection.insert_one(name: 'bang')
4677
- end
4678
-
4679
- it 'does not apply the collation' do
4680
- expect(result).to be_nil
4681
- end
4682
- end
4683
-
4684
- context 'when various options passed in' do
4685
- # w: 2 requires a replica set
4686
- require_topology :replica_set
4687
-
4688
- # https://jira.mongodb.org/browse/RUBY-2306
4689
- min_server_fcv '3.6'
4690
-
4691
- before do
4692
- authorized_collection.delete_many
4693
- authorized_collection.insert_many([{ name: 'test1' }, { name: 'test2' }])
4694
- end
4695
-
4696
- let(:collection) do
4697
- authorized_collection.with(write_concern: {w: 2})
4698
- end
4699
-
4700
- let(:session) do
4701
- authorized_client.start_session
4702
- end
4703
-
4704
- let!(:command) do
4705
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
4706
- collection.find_one_and_delete(selector, session: session, write_concern: {w: 2},
4707
- bypass_document_validation: true, max_time_ms: 300)
4708
- end.command
4709
- end
4710
-
4711
- let(:events) do
4712
- subscriber.command_started_events('findAndModify')
4713
- end
4714
-
4715
- it 'finds and deletes successfully with correct options sent to server' do
4716
- expect(events.length).to eq(1)
4717
- expect(command[:writeConcern]).to_not be_nil
4718
- expect(command[:writeConcern][:w]).to eq(2)
4719
- expect(command[:bypassDocumentValidation]).to eq(true)
4720
- expect(command[:maxTimeMS]).to eq(300)
4721
- end
4722
- end
4723
- end
4724
-
4725
- describe '#find_one_and_update' do
4726
-
4727
- let(:selector) do
4728
- { field: 'test1' }
4729
- end
4730
-
4731
- before do
4732
- authorized_collection.insert_many([{ field: 'test1' }])
4733
- end
4734
-
4735
- context 'when a matching document is found' do
4736
-
4737
- context 'when no options are provided' do
4738
-
4739
- let(:document) do
4740
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4741
- end
4742
-
4743
- it 'returns the original document' do
4744
- expect(document['field']).to eq('test1')
4745
- end
4746
- end
4747
-
4748
- context 'when a session is provided' do
4749
-
4750
- let(:operation) do
4751
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, session: session)
4752
- end
4753
-
4754
- let(:failed_operation) do
4755
- authorized_collection.find_one_and_update({ '$._id' => 1 }, { '$set' => { field: 'testing' }}, session: session)
4756
- end
4757
-
4758
- let(:session) do
4759
- authorized_client.start_session
4760
- end
4761
-
4762
- let(:client) do
4763
- authorized_client
4764
- end
4765
-
4766
- it_behaves_like 'an operation using a session'
4767
- it_behaves_like 'a failed operation using a session'
4768
- end
4769
-
4770
- context 'when no options are provided' do
4771
-
4772
- let(:document) do
4773
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4774
- end
4775
-
4776
- it 'returns the original document' do
4777
- expect(document['field']).to eq('test1')
4778
- end
4779
- end
4780
-
4781
- context 'when return_document options are provided' do
4782
-
4783
- context 'when return_document is :after' do
4784
-
4785
- let(:document) do
4786
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :after)
4787
- end
4788
-
4789
- it 'returns the new document' do
4790
- expect(document['field']).to eq('testing')
4791
- end
4792
- end
4793
-
4794
- context 'when return_document is :before' do
4795
-
4796
- let(:document) do
4797
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :return_document => :before)
4798
- end
4799
-
4800
- it 'returns the original document' do
4801
- expect(document['field']).to eq('test1')
4802
- end
4803
- end
4804
- end
4805
-
4806
- context 'when a projection is provided' do
4807
-
4808
- let(:document) do
4809
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, projection: { _id: 1 })
4810
- end
4811
-
4812
- it 'returns the document with limited fields' do
4813
- expect(document['field']).to be_nil
4814
- expect(document['_id']).to_not be_nil
4815
- end
4816
- end
4817
-
4818
- context 'when a sort is provided' do
4819
-
4820
- let(:document) do
4821
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, sort: { field: 1 })
4822
- end
4823
-
4824
- it 'returns the original document' do
4825
- expect(document['field']).to eq('test1')
4826
- end
4827
- end
4828
- end
4829
-
4830
- context 'when max_time_ms is provided' do
4831
-
4832
- it 'includes the max_time_ms value in the command' do
4833
- expect {
4834
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
4835
- }.to raise_error(Mongo::Error::OperationFailure)
4836
- end
4837
- end
4838
-
4839
- context 'when no matching document is found' do
4840
-
4841
- let(:selector) do
4842
- { field: 'test5' }
4843
- end
4844
-
4845
- let(:document) do
4846
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4847
- end
4848
-
4849
- it 'returns nil' do
4850
- expect(document).to be_nil
4851
- end
4852
- end
4853
-
4854
- context 'when no matching document is found' do
4855
-
4856
- context 'when no upsert options are provided' do
4857
-
4858
- let(:selector) do
4859
- { field: 'test5' }
4860
- end
4861
-
4862
- let(:document) do
4863
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }})
4864
- end
4865
-
4866
- it 'returns nil' do
4867
- expect(document).to be_nil
4868
- end
4869
- end
4870
-
4871
- context 'when upsert options are provided' do
4872
-
4873
- let(:selector) do
4874
- { field: 'test5' }
4875
- end
4876
-
4877
- let(:document) do
4878
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, :upsert => true, :return_document => :after)
4879
- end
4880
-
4881
- it 'returns the new document' do
4882
- expect(document['field']).to eq('testing')
4883
- end
4884
- end
4885
- end
4886
-
4887
- context 'when the operation fails' do
4888
-
4889
- let(:result) do
4890
- authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
4891
- end
4892
-
4893
- it 'raises an OperationFailure' do
4894
- expect {
4895
- result
4896
- }.to raise_exception(Mongo::Error::OperationFailure)
4897
- end
4898
- end
4899
-
4900
- context 'when collection has a validator' do
4901
- min_server_fcv '3.2'
4902
-
4903
- around(:each) do |spec|
4904
- authorized_client[:validating].drop
4905
- authorized_client[:validating,
4906
- :validator => { :a => { '$exists' => true } }].tap do |c|
4907
- c.create
4908
- end
4909
- spec.run
4910
- collection_with_validator.drop
4911
- end
4912
-
4913
- before do
4914
- collection_with_validator.insert_one({ a: 1 })
4915
- end
4916
-
4917
- context 'when the document is valid' do
4918
-
4919
- let(:result) do
4920
- collection_with_validator.find_one_and_update(
4921
- { a: 1 }, { '$inc' => { :a => 1 } }, :return_document => :after)
4922
- end
4923
-
4924
- it 'updates successfully' do
4925
- expect(result['a']).to eq(2)
4926
- end
4927
- end
4928
-
4929
- context 'when the document is invalid' do
4930
-
4931
- context 'when bypass_document_validation is not set' do
4932
-
4933
- let(:result2) do
4934
- collection_with_validator.find_one_and_update(
4935
- { a: 1 }, { '$unset' => { :a => '' } }, :return_document => :after)
4936
- end
4937
-
4938
- it 'raises OperationFailure' do
4939
- expect {
4940
- result2
4941
- }.to raise_exception(Mongo::Error::OperationFailure)
4942
- end
4943
- end
4944
-
4945
- context 'when bypass_document_validation is true' do
4946
-
4947
- let(:result3) do
4948
- collection_with_validator.find_one_and_update(
4949
- { a: 1 }, { '$unset' => { :a => '' } },
4950
- :bypass_document_validation => true,
4951
- :return_document => :after)
4952
- end
4953
-
4954
- it 'updates successfully' do
4955
- expect(result3['a']).to be_nil
4956
- end
4957
- end
4958
- end
4959
- end
4960
-
4961
- context 'when write_concern is provided' do
4962
- min_server_fcv '3.2'
4963
- require_topology :single
4964
-
4965
- it 'uses the write concern' do
4966
- expect {
4967
- authorized_collection.find_one_and_update(selector,
4968
- { '$set' => { field: 'testing' }},
4969
- write_concern: { w: 2 })
4970
- }.to raise_error(Mongo::Error::OperationFailure)
4971
- end
4972
- end
4973
-
4974
- context 'when the collection has a write concern' do
4975
- min_server_fcv '3.2'
4976
- require_topology :single
4977
-
4978
- let(:collection) do
4979
- authorized_collection.with(write: { w: 2 })
4980
- end
4981
-
4982
- it 'uses the write concern' do
4983
- expect {
4984
- collection.find_one_and_update(selector,
4985
- { '$set' => { field: 'testing' }},
4986
- write_concern: { w: 2 })
4987
- }.to raise_error(Mongo::Error::OperationFailure)
4988
- end
4989
- end
4990
-
4991
- context 'when a collation is specified' do
4992
-
4993
- let(:selector) do
4994
- { name: 'BANG' }
4995
- end
4996
-
4997
- let(:result) do
4998
- authorized_collection.find_one_and_update(selector,
4999
- { '$set' => { other: 'doink' } },
5000
- options)
5001
- end
5002
-
5003
- before do
5004
- authorized_collection.insert_one(name: 'bang')
5005
- end
5006
-
5007
- let(:options) do
5008
- { collation: { locale: 'en_US', strength: 2 } }
5009
- end
5010
-
5011
- context 'when the server selected supports collations' do
5012
- min_server_fcv '3.4'
5013
-
5014
- it 'applies the collation' do
5015
- expect(result['name']).to eq('bang')
5016
- expect(authorized_collection.find({ name: 'bang' }, limit: -1).first['other']).to eq('doink')
5017
- end
5018
- end
5019
-
5020
- context 'when the server selected does not support collations' do
5021
- max_server_version '3.2'
5022
-
5023
- it 'raises an exception' do
5024
- expect {
5025
- result
5026
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5027
- end
5028
-
5029
- context 'when a String key is used' do
5030
-
5031
- let(:options) do
5032
- { 'collation' => { locale: 'en_US', strength: 2 } }
5033
- end
5034
-
5035
- it 'raises an exception' do
5036
- expect {
5037
- result
5038
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5039
- end
5040
- end
5041
- end
5042
- end
5043
-
5044
- context 'when there is no collation specified' do
5045
-
5046
- let(:selector) do
5047
- { name: 'BANG' }
5048
- end
5049
-
5050
- let(:result) do
5051
- authorized_collection.find_one_and_update(selector, { '$set' => { other: 'doink' } })
5052
- end
5053
-
5054
- before do
5055
- authorized_collection.insert_one(name: 'bang')
5056
- end
5057
-
5058
- it 'does not apply the collation' do
5059
- expect(result).to be_nil
5060
- end
5061
- end
5062
-
5063
- context 'when arrayFilters is provided' do
5064
-
5065
- let(:selector) do
5066
- { _id: 0 }
5067
- end
5068
-
5069
- context 'when the server supports arrayFilters' do
5070
- min_server_fcv '3.6'
5071
-
5072
- before do
5073
- authorized_collection.insert_one(_id: 0, x: [{ y: 1 }, { y: 2 }, { y: 3 }])
5074
- end
5075
-
5076
- let(:result) do
5077
- authorized_collection.find_one_and_update(selector,
5078
- { '$set' => { 'x.$[i].y' => 5 } },
5079
- options)
5080
- end
5081
-
5082
- context 'when a Symbol key is used' do
5083
-
5084
- let(:options) do
5085
- { array_filters: [{ 'i.y' => 3 }] }
5086
- end
5087
-
5088
-
5089
- it 'applies the arrayFilters' do
5090
- expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
5091
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
5092
- end
5093
- end
5094
-
5095
- context 'when a String key is used' do
5096
-
5097
- let(:options) do
5098
- { 'array_filters' => [{ 'i.y' => 3 }] }
5099
- end
5100
-
5101
- it 'applies the arrayFilters' do
5102
- expect(result['x']).to eq([{ 'y' => 1 }, { 'y' => 2 }, { 'y' => 3 }])
5103
- expect(authorized_collection.find(selector).first['x'].last['y']).to eq(5)
5104
- end
5105
- end
5106
- end
5107
-
5108
- context 'when the server selected does not support arrayFilters' do
5109
- max_server_version '3.4'
5110
-
5111
- let(:result) do
5112
- authorized_collection.find_one_and_update(selector,
5113
- { '$set' => { 'x.$[i].y' => 5 } },
5114
- options)
5115
- end
5116
-
5117
- context 'when a Symbol key is used' do
5118
-
5119
- let(:options) do
5120
- { array_filters: [{ 'i.y' => 3 }] }
5121
- end
5122
-
5123
- it 'raises an exception' do
5124
- expect {
5125
- result
5126
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
5127
- end
5128
- end
5129
-
5130
- context 'when a String key is used' do
5131
-
5132
- let(:options) do
5133
- { 'array_filters' => [{ 'i.y' => 3 }] }
5134
- end
5135
-
5136
- it 'raises an exception' do
5137
- expect {
5138
- result
5139
- }.to raise_exception(Mongo::Error::UnsupportedArrayFilters)
5140
- end
5141
- end
5142
- end
5143
- end
5144
-
5145
- context 'when various options passed in' do
5146
- # w: 2 requires a replica set
5147
- require_topology :replica_set
5148
-
5149
- # https://jira.mongodb.org/browse/RUBY-2306
5150
- min_server_fcv '3.6'
5151
-
5152
- let(:session) do
5153
- authorized_client.start_session
5154
- end
5155
-
5156
- let(:events) do
5157
- subscriber.command_started_events('findAndModify')
5158
- end
5159
-
5160
- let(:collection) do
5161
- authorized_collection.with(write_concern: {w: 2})
5162
- end
5163
-
5164
- let(:selector) do
5165
- {field: 'test1'}
5166
- end
5167
-
5168
- before do
5169
- collection.insert_one({field: 'test1'}, session: session)
5170
- end
5171
-
5172
- let!(:command) do
5173
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
5174
- collection.find_one_and_update(selector, { '$set' => {field: 'testing'}},
5175
- :return_document => :after, write_concern: {w: 1}, upsert: true,
5176
- bypass_document_validation: true, max_time_ms: 100, session: session)
5177
- end.command
5178
- end
5179
-
5180
- it 'find and updates successfully with correct options sent to server' do
5181
- expect(events.length).to eq(1)
5182
- expect(command[:writeConcern]).to_not be_nil
5183
- expect(command[:writeConcern][:w]).to eq(1)
5184
- expect(command[:upsert]).to eq(true)
5185
- expect(command[:bypassDocumentValidation]).to be(true)
5186
- expect(command[:maxTimeMS]).to eq(100)
5187
- end
5188
- end
5189
- end
5190
-
5191
- describe '#find_one_and_replace' do
5192
-
5193
- before do
5194
- authorized_collection.insert_many([{ field: 'test1', other: 'sth' }])
5195
- end
5196
-
5197
- let(:selector) do
5198
- { field: 'test1' }
5199
- end
5200
-
5201
- context 'when a matching document is found' do
5202
-
5203
- context 'when no options are provided' do
5204
-
5205
- let(:document) do
5206
- authorized_collection.find_one_and_replace(selector, { field: 'testing' })
5207
- end
5208
-
5209
- it 'returns the original document' do
5210
- expect(document['field']).to eq('test1')
5211
- end
5212
- end
5213
-
5214
- context 'when a session is provided' do
5215
-
5216
- let(:operation) do
5217
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, session: session)
5218
- end
5219
-
5220
- let(:failed_operation) do
5221
- authorized_collection.find_one_and_replace({ '$._id' => 1}, { field: 'testing' }, session: session)
5222
- end
5223
-
5224
- let(:session) do
5225
- authorized_client.start_session
5226
- end
5227
-
5228
- let(:client) do
5229
- authorized_client
5230
- end
5231
-
5232
- it_behaves_like 'an operation using a session'
5233
- it_behaves_like 'a failed operation using a session'
5234
- end
5235
-
5236
- context 'when return_document options are provided' do
5237
-
5238
- context 'when return_document is :after' do
5239
-
5240
- let(:document) do
5241
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :after)
5242
- end
5243
-
5244
- it 'returns the new document' do
5245
- expect(document['field']).to eq('testing')
5246
- end
5247
- end
5248
-
5249
- context 'when return_document is :before' do
5250
-
5251
- let(:document) do
5252
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :return_document => :before)
5253
- end
5254
-
5255
- it 'returns the original document' do
5256
- expect(document['field']).to eq('test1')
5257
- end
5258
- end
5259
- end
5260
-
5261
- context 'when a projection is provided' do
5262
-
5263
- let(:document) do
5264
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, projection: { _id: 1 })
5265
- end
5266
-
5267
- it 'returns the document with limited fields' do
5268
- expect(document['field']).to be_nil
5269
- expect(document['_id']).to_not be_nil
5270
- end
5271
- end
5272
-
5273
- context 'when a sort is provided' do
5274
-
5275
- let(:document) do
5276
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :sort => { field: 1 })
5277
- end
5278
-
5279
- it 'returns the original document' do
5280
- expect(document['field']).to eq('test1')
5281
- end
5282
- end
5283
- end
5284
-
5285
- context 'when no matching document is found' do
5286
-
5287
- context 'when no upsert options are provided' do
5288
-
5289
- let(:selector) do
5290
- { field: 'test5' }
5291
- end
5292
-
5293
- let(:document) do
5294
- authorized_collection.find_one_and_replace(selector, { field: 'testing' })
5295
- end
5296
-
5297
- it 'returns nil' do
5298
- expect(document).to be_nil
5299
- end
5300
- end
5301
-
5302
- context 'when upsert options are provided' do
5303
-
5304
- let(:selector) do
5305
- { field: 'test5' }
5306
- end
5307
-
5308
- let(:document) do
5309
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, :upsert => true, :return_document => :after)
5310
- end
5311
-
5312
- it 'returns the new document' do
5313
- expect(document['field']).to eq('testing')
5314
- end
5315
- end
5316
- end
5317
-
5318
- context 'when max_time_ms is provided' do
5319
-
5320
- it 'includes the max_time_ms value in the command' do
5321
- expect {
5322
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
5323
- }.to raise_error(Mongo::Error::OperationFailure)
5324
- end
5325
- end
5326
-
5327
- context 'when the operation fails' do
5328
-
5329
- let(:result) do
5330
- authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
5331
- end
5332
-
5333
- it 'raises an OperationFailure' do
5334
- expect {
5335
- result
5336
- }.to raise_exception(Mongo::Error::OperationFailure)
5337
- end
5338
- end
5339
-
5340
- context 'when collection has a validator' do
5341
- min_server_fcv '3.2'
5342
-
5343
- around(:each) do |spec|
5344
- authorized_client[:validating].drop
5345
- authorized_client[:validating,
5346
- :validator => { :a => { '$exists' => true } }].tap do |c|
5347
- c.create
5348
- end
5349
- spec.run
5350
- collection_with_validator.drop
5351
- end
5352
-
5353
- before do
5354
- collection_with_validator.insert_one({ a: 1 })
5355
- end
5356
-
5357
- context 'when the document is valid' do
5358
-
5359
- let(:result) do
5360
- collection_with_validator.find_one_and_replace(
5361
- { a: 1 }, { a: 5 }, :return_document => :after)
5362
- end
5363
-
5364
- it 'replaces successfully when document is valid' do
5365
- expect(result[:a]).to eq(5)
5366
- end
5367
- end
5368
-
5369
- context 'when the document is invalid' do
5370
-
5371
- context 'when bypass_document_validation is not set' do
5372
-
5373
- let(:result2) do
5374
- collection_with_validator.find_one_and_replace(
5375
- { a: 1 }, { x: 5 }, :return_document => :after)
5376
- end
5377
-
5378
- it 'raises OperationFailure' do
5379
- expect {
5380
- result2
5381
- }.to raise_exception(Mongo::Error::OperationFailure)
5382
- end
5383
- end
5384
-
5385
- context 'when bypass_document_validation is true' do
5386
-
5387
- let(:result3) do
5388
- collection_with_validator.find_one_and_replace(
5389
- { a: 1 }, { x: 1 }, :bypass_document_validation => true,
5390
- :return_document => :after)
5391
- end
5392
-
5393
- it 'replaces successfully' do
5394
- expect(result3[:x]).to eq(1)
5395
- expect(result3[:a]).to be_nil
5396
- end
5397
- end
5398
- end
5399
- end
5400
-
5401
- context 'when write_concern is provided' do
5402
- min_server_fcv '3.2'
5403
- require_topology :single
5404
-
5405
- it 'uses the write concern' do
5406
- expect {
5407
- authorized_collection.find_one_and_replace(selector,
5408
- { field: 'testing' },
5409
- write_concern: { w: 2 })
5410
- }.to raise_error(Mongo::Error::OperationFailure)
5411
- end
5412
- end
5413
-
5414
- context 'when the collection has a write concern' do
5415
- min_server_fcv '3.2'
5416
- require_topology :single
5417
-
5418
- let(:collection) do
5419
- authorized_collection.with(write: { w: 2 })
5420
- end
5421
-
5422
- it 'uses the write concern' do
5423
- expect {
5424
- collection.find_one_and_replace(selector,
5425
- { field: 'testing' },
5426
- write_concern: { w: 2 })
5427
- }.to raise_error(Mongo::Error::OperationFailure)
5428
- end
5429
- end
5430
-
5431
- context 'when collation is provided' do
5432
-
5433
- let(:selector) do
5434
- { name: 'BANG' }
5435
- end
5436
-
5437
- let(:result) do
5438
- authorized_collection.find_one_and_replace(selector,
5439
- { name: 'doink' },
5440
- options)
5441
- end
5442
-
5443
- before do
5444
- authorized_collection.insert_one(name: 'bang')
5445
- end
5446
-
5447
- let(:options) do
5448
- { collation: { locale: 'en_US', strength: 2 } }
5449
- end
5450
-
5451
- context 'when the server selected supports collations' do
5452
- min_server_fcv '3.4'
5453
-
5454
- it 'applies the collation' do
5455
- expect(result['name']).to eq('bang')
5456
- expect(authorized_collection.find(name: 'doink').count).to eq(1)
5457
- end
5458
- end
5459
-
5460
- context 'when the server selected does not support collations' do
5461
- max_server_version '3.2'
5462
-
5463
- it 'raises an exception' do
5464
- expect {
5465
- result
5466
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5467
- end
5468
-
5469
- context 'when a String key is used' do
5470
-
5471
- let(:options) do
5472
- { 'collation' => { locale: 'en_US', strength: 2 } }
5473
- end
5474
-
5475
- it 'raises an exception' do
5476
- expect {
5477
- result
5478
- }.to raise_exception(Mongo::Error::UnsupportedCollation)
5479
- end
5480
- end
5481
- end
5482
- end
5483
-
5484
- context 'when collation is not specified' do
5485
-
5486
- let(:selector) do
5487
- { name: 'BANG' }
5488
- end
5489
-
5490
- let(:result) do
5491
- authorized_collection.find_one_and_replace(selector, { name: 'doink' })
5492
- end
5493
-
5494
- before do
5495
- authorized_collection.insert_one(name: 'bang')
5496
- end
5497
-
5498
- it 'does not apply the collation' do
5499
- expect(result).to be_nil
5500
- end
5501
- end
5502
-
5503
- context 'when various options passed in' do
5504
- # https://jira.mongodb.org/browse/RUBY-2306
5505
- min_server_fcv '3.6'
5506
-
5507
- before do
5508
- authorized_collection.insert_one({field: 'test1'})
5509
- end
5510
-
5511
- let(:session) do
5512
- authorized_client.start_session
5513
- end
5514
-
5515
- let(:events) do
5516
- subscriber.command_started_events('findAndModify')
5517
- end
5518
-
5519
- let(:collection) do
5520
- authorized_collection.with(write_concern: { w: 2 })
5521
- end
5522
-
5523
- let!(:command) do
5524
- Utils.get_command_event(authorized_client, 'findAndModify') do |client|
5525
- collection.find_one_and_replace(selector, { '$set' => {field: 'test5'}},
5526
- :return_document => :after, write_concern: {w: 1}, session: session,
5527
- upsert: true, bypass_document_validation: false, max_time_ms: 200)
5528
- end.command
5529
- end
5530
-
5531
- it 'find and replaces successfully with correct options sent to server' do
5532
- expect(events.length).to eq(1)
5533
- expect(command[:writeConcern]).to_not be_nil
5534
- expect(command[:writeConcern][:w]).to eq(1)
5535
- expect(command[:upsert]).to be(true)
5536
- expect(command[:bypassDocumentValidation]).to be_nil
5537
- expect(command[:maxTimeMS]).to eq(200)
5538
- end
683
+ it 'includes the namespace' do
684
+ expect(authorized_collection.inspect).to include(authorized_collection.namespace)
5539
685
  end
5540
686
  end
5541
687