mongo 2.14.1 → 2.15.0.alpha

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