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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/README.md +4 -1
- data/Rakefile +8 -15
- data/lib/mongo/auth/aws/conversation.rb +1 -4
- data/lib/mongo/auth/base.rb +13 -7
- data/lib/mongo/auth/conversation_base.rb +32 -0
- data/lib/mongo/auth/cr/conversation.rb +6 -29
- data/lib/mongo/auth/gssapi/conversation.rb +4 -15
- data/lib/mongo/auth/ldap/conversation.rb +3 -14
- data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
- data/lib/mongo/auth/scram_conversation_base.rb +7 -34
- data/lib/mongo/auth/user/view.rb +16 -9
- data/lib/mongo/auth/x509/conversation.rb +4 -25
- data/lib/mongo/bulk_write.rb +21 -18
- data/lib/mongo/client.rb +82 -6
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
- data/lib/mongo/cluster.rb +19 -2
- data/lib/mongo/collection/view/aggregation.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +1 -1
- data/lib/mongo/collection/view/iterable.rb +7 -17
- data/lib/mongo/collection/view/map_reduce.rb +2 -2
- data/lib/mongo/collection/view/readable.rb +42 -20
- data/lib/mongo/collection/view/writable.rb +14 -14
- data/lib/mongo/collection.rb +6 -6
- data/lib/mongo/cursor.rb +2 -12
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/database.rb +8 -3
- data/lib/mongo/error/bulk_write_error.rb +17 -3
- data/lib/mongo/error/internal_driver_error.rb +22 -0
- data/lib/mongo/error/operation_failure.rb +21 -2
- data/lib/mongo/error/parser.rb +65 -12
- data/lib/mongo/error/server_api_conflict.rb +23 -0
- data/lib/mongo/error/server_api_not_supported.rb +24 -0
- data/lib/mongo/error/unmet_dependency.rb +21 -0
- data/lib/mongo/error.rb +9 -1
- data/lib/mongo/index/view.rb +21 -11
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
- data/lib/mongo/monitoring.rb +13 -4
- data/lib/mongo/operation/collections_info/command.rb +2 -2
- data/lib/mongo/operation/collections_info.rb +18 -1
- data/lib/mongo/operation/context.rb +99 -0
- data/lib/mongo/operation/indexes.rb +15 -1
- data/lib/mongo/operation/insert/command.rb +2 -2
- data/lib/mongo/operation/insert/legacy.rb +2 -2
- data/lib/mongo/operation/insert/op_msg.rb +2 -2
- data/lib/mongo/operation/list_collections/result.rb +4 -1
- data/lib/mongo/operation/parallel_scan/command.rb +2 -1
- data/lib/mongo/operation/result.rb +2 -0
- data/lib/mongo/operation/shared/executable.rb +24 -14
- data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
- data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
- data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
- data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
- data/lib/mongo/operation/shared/response_handling.rb +23 -23
- data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
- data/lib/mongo/operation/shared/write.rb +8 -18
- data/lib/mongo/operation.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +51 -5
- data/lib/mongo/protocol/message.rb +20 -2
- data/lib/mongo/protocol/msg.rb +38 -13
- data/lib/mongo/protocol/query.rb +11 -11
- data/lib/mongo/query_cache.rb +30 -0
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server/app_metadata.rb +52 -18
- data/lib/mongo/server/connection.rb +5 -0
- data/lib/mongo/server/connection_base.rb +13 -10
- data/lib/mongo/server/connection_pool.rb +6 -2
- data/lib/mongo/server/description/features.rb +9 -8
- data/lib/mongo/server/description.rb +4 -0
- data/lib/mongo/server/monitor/app_metadata.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +9 -10
- data/lib/mongo/server/monitor.rb +20 -1
- data/lib/mongo/server/pending_connection.rb +24 -6
- data/lib/mongo/server/push_monitor.rb +11 -1
- data/lib/mongo/server.rb +7 -1
- data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
- data/lib/mongo/session/session_pool.rb +4 -2
- data/lib/mongo/session.rb +2 -2
- data/lib/mongo/socket/ssl.rb +8 -0
- data/lib/mongo/socket.rb +29 -4
- data/lib/mongo/uri/options_mapper.rb +38 -0
- data/lib/mongo/utils.rb +15 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +23 -0
- data/spec/README.md +24 -1
- data/spec/integration/auth_spec.rb +25 -15
- data/spec/integration/bulk_write_error_message_spec.rb +41 -0
- data/spec/integration/change_stream_spec.rb +4 -4
- data/spec/integration/command_monitoring_spec.rb +2 -2
- data/spec/integration/connection_spec.rb +2 -0
- data/spec/integration/docs_examples_spec.rb +8 -1
- data/spec/integration/fork_reconnect_spec.rb +4 -1
- data/spec/integration/ocsp_verifier_spec.rb +13 -7
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +90 -0
- data/spec/integration/query_cache_spec.rb +0 -45
- data/spec/integration/reconnect_spec.rb +1 -1
- data/spec/integration/snappy_compression_spec.rb +25 -0
- data/spec/integration/srv_monitoring_spec.rb +1 -1
- data/spec/integration/transactions_examples_spec.rb +6 -0
- data/spec/integration/zlib_compression_spec.rb +1 -1
- data/spec/integration/zstd_compression_spec.rb +26 -0
- data/spec/lite_spec_helper.rb +7 -1
- data/spec/mongo/address_spec.rb +15 -11
- data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
- data/spec/mongo/auth/ldap_spec.rb +5 -1
- data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
- data/spec/mongo/client_construction_spec.rb +207 -33
- data/spec/mongo/client_spec.rb +17 -0
- data/spec/mongo/cluster_spec.rb +1 -0
- data/spec/mongo/collection/view/explainable_spec.rb +1 -1
- data/spec/mongo/collection/view/readable_spec.rb +33 -19
- data/spec/mongo/collection_crud_spec.rb +4357 -0
- data/spec/mongo/collection_ddl_spec.rb +534 -0
- data/spec/mongo/collection_spec.rb +5 -4859
- data/spec/mongo/database_spec.rb +66 -4
- data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
- data/spec/mongo/error/parser_spec.rb +37 -6
- data/spec/mongo/index/view_spec.rb +4 -0
- data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
- data/spec/mongo/operation/aggregate_spec.rb +2 -1
- data/spec/mongo/operation/collections_info_spec.rb +4 -1
- data/spec/mongo/operation/command_spec.rb +6 -3
- data/spec/mongo/operation/create_index_spec.rb +6 -3
- data/spec/mongo/operation/create_user_spec.rb +6 -3
- data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
- data/spec/mongo/operation/delete_spec.rb +11 -7
- data/spec/mongo/operation/drop_index_spec.rb +6 -2
- data/spec/mongo/operation/find/legacy_spec.rb +3 -1
- data/spec/mongo/operation/get_more_spec.rb +3 -1
- data/spec/mongo/operation/indexes_spec.rb +5 -1
- data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
- data/spec/mongo/operation/insert_spec.rb +15 -12
- data/spec/mongo/operation/map_reduce_spec.rb +5 -2
- data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
- data/spec/mongo/operation/remove_user_spec.rb +6 -3
- data/spec/mongo/operation/result_spec.rb +1 -1
- data/spec/mongo/operation/update/bulk_spec.rb +9 -6
- data/spec/mongo/operation/update_spec.rb +10 -7
- data/spec/mongo/operation/update_user_spec.rb +4 -1
- data/spec/mongo/protocol/compressed_spec.rb +26 -12
- data/spec/mongo/query_cache_middleware_spec.rb +55 -0
- data/spec/mongo/retryable_spec.rb +3 -2
- data/spec/mongo/server/app_metadata_shared.rb +7 -33
- data/spec/mongo/server/app_metadata_spec.rb +2 -0
- data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
- data/spec/mongo/server/connection_pool_spec.rb +1 -1
- data/spec/mongo/server/connection_spec.rb +24 -17
- data/spec/mongo/server/monitor/connection_spec.rb +17 -7
- data/spec/mongo/server/monitor_spec.rb +9 -1
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
- data/spec/mongo/server_spec.rb +15 -2
- data/spec/mongo/socket/ssl_spec.rb +40 -0
- data/spec/mongo/socket_spec.rb +2 -2
- data/spec/mongo/tls_context_hooks_spec.rb +37 -0
- data/spec/runners/connection_string.rb +0 -4
- data/spec/runners/crud/requirement.rb +40 -3
- data/spec/runners/crud/verifier.rb +8 -0
- data/spec/runners/transactions/operation.rb +1 -1
- data/spec/runners/transactions/test.rb +1 -0
- data/spec/runners/unified/assertions.rb +249 -0
- data/spec/runners/unified/change_stream_operations.rb +26 -0
- data/spec/runners/unified/crud_operations.rb +199 -0
- data/spec/runners/unified/ddl_operations.rb +96 -0
- data/spec/runners/unified/entity_map.rb +39 -0
- data/spec/runners/unified/error.rb +25 -0
- data/spec/runners/unified/event_subscriber.rb +91 -0
- data/spec/runners/unified/exceptions.rb +21 -0
- data/spec/runners/unified/grid_fs_operations.rb +55 -0
- data/spec/runners/unified/support_operations.rb +250 -0
- data/spec/runners/unified/test.rb +393 -0
- data/spec/runners/unified/test_group.rb +28 -0
- data/spec/runners/unified/using_hash.rb +31 -0
- data/spec/runners/unified.rb +96 -0
- data/spec/shared/lib/mrss/cluster_config.rb +0 -3
- data/spec/shared/lib/mrss/docker_runner.rb +0 -3
- data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
- data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
- data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
- data/spec/shared/shlib/server.sh +1 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/spec_tests/crud_unified_spec.rb +10 -0
- data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
- data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
- data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
- data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
- data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
- data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
- data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
- data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
- data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
- data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
- data/spec/spec_tests/unified_spec.rb +15 -0
- data/spec/spec_tests/uri_options_spec.rb +16 -0
- data/spec/spec_tests/versioned_api_spec.rb +10 -0
- data/spec/support/client_registry.rb +4 -8
- data/spec/support/client_registry_macros.rb +4 -4
- data/spec/support/common_shortcuts.rb +15 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_config.rb +42 -11
- data/spec/support/utils.rb +64 -3
- data.tar.gz.sig +0 -0
- metadata +1005 -915
- metadata.gz.sig +0 -0
- data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
- data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
- data/spec/integration/secondary_reads_spec.rb +0 -102
- 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 '#
|
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
|
-
|
1126
|
-
|
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
|
-
|
1133
|
-
|
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
|
|