mongo 2.13.0.beta1 → 2.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -5
- data/Rakefile +50 -9
- data/lib/mongo.rb +13 -2
- data/lib/mongo/address.rb +1 -1
- data/lib/mongo/address/ipv4.rb +1 -1
- data/lib/mongo/address/ipv6.rb +1 -1
- data/lib/mongo/auth/aws/request.rb +31 -5
- data/lib/mongo/bulk_write.rb +18 -0
- data/lib/mongo/caching_cursor.rb +74 -0
- data/lib/mongo/client.rb +238 -31
- data/lib/mongo/cluster.rb +56 -20
- data/lib/mongo/cluster/sdam_flow.rb +13 -10
- data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
- data/lib/mongo/cluster/topology/sharded.rb +1 -1
- data/lib/mongo/cluster/topology/single.rb +2 -2
- data/lib/mongo/collection.rb +66 -24
- data/lib/mongo/collection/view.rb +24 -20
- data/lib/mongo/collection/view/aggregation.rb +25 -4
- data/lib/mongo/collection/view/builder/find_command.rb +38 -18
- data/lib/mongo/collection/view/explainable.rb +27 -8
- data/lib/mongo/collection/view/iterable.rb +72 -12
- data/lib/mongo/collection/view/readable.rb +19 -3
- data/lib/mongo/collection/view/writable.rb +55 -5
- data/lib/mongo/crypt/encryption_io.rb +6 -6
- data/lib/mongo/cursor.rb +16 -3
- data/lib/mongo/database.rb +37 -4
- data/lib/mongo/database/view.rb +18 -3
- data/lib/mongo/distinguishing_semaphore.rb +55 -0
- data/lib/mongo/error.rb +5 -0
- data/lib/mongo/error/invalid_read_concern.rb +28 -0
- data/lib/mongo/error/invalid_server_auth_host.rb +22 -0
- data/lib/mongo/error/invalid_session.rb +2 -1
- data/lib/mongo/error/operation_failure.rb +11 -5
- data/lib/mongo/error/server_certificate_revoked.rb +22 -0
- data/lib/mongo/error/sessions_not_supported.rb +35 -0
- data/lib/mongo/error/unsupported_option.rb +14 -12
- data/lib/mongo/event/base.rb +6 -0
- data/lib/mongo/grid/file.rb +5 -0
- data/lib/mongo/grid/file/chunk.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +15 -13
- data/lib/mongo/grid/stream/write.rb +9 -3
- data/lib/mongo/index/view.rb +3 -0
- data/lib/mongo/lint.rb +2 -1
- data/lib/mongo/logger.rb +3 -3
- data/lib/mongo/monitoring.rb +38 -0
- data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
- data/lib/mongo/monitoring/event/command_failed.rb +11 -0
- data/lib/mongo/monitoring/event/command_started.rb +37 -2
- data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
- data/lib/mongo/monitoring/event/server_closed.rb +1 -1
- data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
- data/lib/mongo/monitoring/event/server_opening.rb +1 -1
- data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
- data/lib/mongo/monitoring/publishable.rb +6 -3
- data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
- data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
- data/lib/mongo/operation.rb +2 -0
- data/lib/mongo/operation/aggregate/result.rb +9 -8
- data/lib/mongo/operation/collections_info/command.rb +5 -0
- data/lib/mongo/operation/collections_info/result.rb +18 -1
- data/lib/mongo/operation/delete/bulk_result.rb +2 -0
- data/lib/mongo/operation/delete/result.rb +3 -0
- data/lib/mongo/operation/explain/command.rb +4 -0
- data/lib/mongo/operation/explain/legacy.rb +4 -0
- data/lib/mongo/operation/explain/op_msg.rb +6 -0
- data/lib/mongo/operation/explain/result.rb +3 -0
- data/lib/mongo/operation/find/legacy/result.rb +2 -0
- data/lib/mongo/operation/find/result.rb +13 -0
- data/lib/mongo/operation/get_more/result.rb +3 -0
- data/lib/mongo/operation/indexes/result.rb +5 -0
- data/lib/mongo/operation/insert/bulk_result.rb +5 -0
- data/lib/mongo/operation/insert/result.rb +5 -0
- data/lib/mongo/operation/list_collections/result.rb +5 -0
- data/lib/mongo/operation/map_reduce/result.rb +10 -0
- data/lib/mongo/operation/parallel_scan/result.rb +4 -0
- data/lib/mongo/operation/result.rb +35 -6
- data/lib/mongo/operation/shared/bypass_document_validation.rb +1 -0
- data/lib/mongo/operation/shared/causal_consistency_supported.rb +1 -0
- data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +2 -0
- data/lib/mongo/operation/shared/executable.rb +1 -0
- data/lib/mongo/operation/shared/idable.rb +2 -1
- data/lib/mongo/operation/shared/limited.rb +1 -0
- data/lib/mongo/operation/shared/object_id_generator.rb +1 -0
- data/lib/mongo/operation/shared/result/aggregatable.rb +1 -0
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -0
- data/lib/mongo/operation/shared/specifiable.rb +1 -0
- data/lib/mongo/operation/shared/write.rb +1 -0
- data/lib/mongo/operation/shared/write_concern_supported.rb +1 -0
- data/lib/mongo/operation/update/legacy/result.rb +7 -0
- data/lib/mongo/operation/update/result.rb +8 -0
- data/lib/mongo/operation/users_info/result.rb +3 -0
- data/lib/mongo/protocol/message.rb +47 -10
- data/lib/mongo/protocol/msg.rb +34 -1
- data/lib/mongo/protocol/query.rb +36 -0
- data/lib/mongo/protocol/serializers.rb +5 -2
- data/lib/mongo/query_cache.rb +242 -0
- data/lib/mongo/retryable.rb +8 -1
- data/lib/mongo/server.rb +15 -4
- data/lib/mongo/server/app_metadata.rb +27 -3
- data/lib/mongo/server/connection.rb +4 -4
- data/lib/mongo/server/connection_base.rb +38 -12
- data/lib/mongo/server/connection_common.rb +2 -2
- data/lib/mongo/server/connection_pool.rb +3 -0
- data/lib/mongo/server/description.rb +13 -1
- data/lib/mongo/server/monitor.rb +76 -44
- data/lib/mongo/server/monitor/connection.rb +57 -9
- data/lib/mongo/server/pending_connection.rb +14 -4
- data/lib/mongo/server/push_monitor.rb +173 -0
- data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
- data/lib/mongo/server_selector.rb +0 -1
- data/lib/mongo/server_selector/base.rb +583 -1
- data/lib/mongo/server_selector/nearest.rb +1 -6
- data/lib/mongo/server_selector/primary.rb +1 -6
- data/lib/mongo/server_selector/primary_preferred.rb +7 -10
- data/lib/mongo/server_selector/secondary.rb +1 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
- data/lib/mongo/session.rb +7 -1
- data/lib/mongo/socket.rb +26 -12
- data/lib/mongo/socket/ocsp_cache.rb +97 -0
- data/lib/mongo/socket/ocsp_verifier.rb +368 -0
- data/lib/mongo/socket/ssl.rb +46 -25
- data/lib/mongo/socket/tcp.rb +1 -1
- data/lib/mongo/srv/monitor.rb +7 -13
- data/lib/mongo/srv/resolver.rb +14 -10
- data/lib/mongo/timeout.rb +2 -0
- data/lib/mongo/topology_version.rb +9 -0
- data/lib/mongo/uri.rb +21 -390
- data/lib/mongo/uri/options_mapper.rb +582 -0
- data/lib/mongo/uri/srv_protocol.rb +3 -2
- data/lib/mongo/utils.rb +73 -0
- data/lib/mongo/version.rb +1 -1
- data/spec/NOTES.aws-auth.md +12 -7
- data/spec/README.aws-auth.md +2 -2
- data/spec/README.md +63 -1
- data/spec/integration/awaited_ismaster_spec.rb +28 -0
- data/spec/integration/bson_symbol_spec.rb +4 -2
- data/spec/integration/bulk_write_spec.rb +67 -0
- data/spec/integration/change_stream_examples_spec.rb +6 -2
- data/spec/integration/change_stream_spec.rb +1 -1
- data/spec/integration/check_clean_slate_spec.rb +16 -0
- data/spec/integration/client_authentication_options_spec.rb +92 -28
- data/spec/integration/client_construction_spec.rb +1 -0
- data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +9 -5
- data/spec/integration/connect_single_rs_name_spec.rb +5 -2
- data/spec/integration/connection_pool_populator_spec.rb +4 -2
- data/spec/integration/connection_spec.rb +7 -4
- data/spec/integration/crud_spec.rb +4 -4
- data/spec/integration/cursor_reaping_spec.rb +54 -18
- data/spec/integration/docs_examples_spec.rb +6 -0
- data/spec/integration/fork_reconnect_spec.rb +56 -1
- data/spec/integration/grid_fs_bucket_spec.rb +48 -0
- data/spec/integration/heartbeat_events_spec.rb +4 -23
- data/spec/integration/ocsp_connectivity_spec.rb +26 -0
- data/spec/integration/ocsp_verifier_cache_spec.rb +188 -0
- data/spec/integration/ocsp_verifier_spec.rb +334 -0
- data/spec/integration/query_cache_spec.rb +1045 -0
- data/spec/integration/query_cache_transactions_spec.rb +190 -0
- data/spec/integration/read_concern_spec.rb +1 -1
- data/spec/integration/retryable_errors_spec.rb +1 -1
- data/spec/integration/retryable_writes/retryable_writes_40_and_newer_spec.rb +1 -0
- data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +4 -2
- data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
- data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +122 -15
- data/spec/integration/sdam_events_spec.rb +80 -6
- data/spec/integration/sdam_prose_spec.rb +64 -0
- data/spec/integration/server_monitor_spec.rb +25 -1
- data/spec/integration/server_selection_spec.rb +36 -0
- data/spec/integration/size_limit_spec.rb +23 -5
- data/spec/integration/srv_monitoring_spec.rb +38 -3
- data/spec/integration/srv_spec.rb +56 -0
- data/spec/integration/ssl_uri_options_spec.rb +2 -2
- data/spec/integration/transactions_examples_spec.rb +17 -7
- data/spec/integration/zlib_compression_spec.rb +25 -0
- data/spec/lite_spec_helper.rb +20 -9
- data/spec/mongo/address_spec.rb +1 -1
- data/spec/mongo/auth/aws/request_region_spec.rb +42 -0
- data/spec/mongo/auth/aws/request_spec.rb +76 -0
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/auth/user_spec.rb +1 -1
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/caching_cursor_spec.rb +70 -0
- data/spec/mongo/client_construction_spec.rb +386 -3
- data/spec/mongo/client_encryption_spec.rb +16 -10
- data/spec/mongo/client_spec.rb +85 -3
- data/spec/mongo/cluster/topology/replica_set_spec.rb +53 -10
- data/spec/mongo/cluster/topology/sharded_spec.rb +1 -1
- data/spec/mongo/cluster/topology/single_spec.rb +19 -8
- data/spec/mongo/cluster/topology/unknown_spec.rb +1 -1
- data/spec/mongo/cluster/topology_spec.rb +1 -1
- data/spec/mongo/cluster_spec.rb +37 -35
- data/spec/mongo/collection/view/change_stream_resume_spec.rb +7 -7
- data/spec/mongo/collection/view/explainable_spec.rb +87 -4
- data/spec/mongo/collection/view/map_reduce_spec.rb +2 -0
- data/spec/mongo/collection/view/readable_spec.rb +36 -0
- data/spec/mongo/collection_spec.rb +572 -0
- data/spec/mongo/crypt/auto_decryption_context_spec.rb +1 -1
- data/spec/mongo/crypt/auto_encryption_context_spec.rb +1 -1
- data/spec/mongo/crypt/binary_spec.rb +1 -6
- data/spec/mongo/crypt/binding/binary_spec.rb +1 -6
- data/spec/mongo/crypt/binding/context_spec.rb +2 -7
- data/spec/mongo/crypt/binding/helpers_spec.rb +1 -6
- data/spec/mongo/crypt/binding/mongocrypt_spec.rb +2 -7
- data/spec/mongo/crypt/binding/status_spec.rb +1 -6
- data/spec/mongo/crypt/binding/version_spec.rb +1 -6
- data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
- data/spec/mongo/crypt/explicit_decryption_context_spec.rb +1 -1
- data/spec/mongo/crypt/explicit_encryption_context_spec.rb +1 -1
- data/spec/mongo/crypt/status_spec.rb +1 -6
- data/spec/mongo/database_spec.rb +353 -8
- data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
- data/spec/mongo/error/no_server_available_spec.rb +1 -1
- data/spec/mongo/error/operation_failure_spec.rb +40 -0
- data/spec/mongo/index/view_spec.rb +148 -2
- data/spec/mongo/logger_spec.rb +13 -11
- data/spec/mongo/monitoring/event/server_closed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
- data/spec/mongo/monitoring/event/server_opening_spec.rb +1 -1
- data/spec/mongo/monitoring/event/topology_changed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/topology_closed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/topology_opening_spec.rb +1 -1
- data/spec/mongo/operation/delete/op_msg_spec.rb +3 -3
- data/spec/mongo/operation/insert/command_spec.rb +2 -2
- data/spec/mongo/operation/insert/op_msg_spec.rb +3 -3
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +1 -1
- data/spec/mongo/operation/update/command_spec.rb +2 -2
- data/spec/mongo/operation/update/op_msg_spec.rb +3 -3
- data/spec/mongo/protocol/msg_spec.rb +10 -0
- data/spec/mongo/query_cache_spec.rb +280 -0
- data/spec/mongo/semaphore_spec.rb +51 -0
- data/spec/mongo/server/app_metadata_shared.rb +82 -2
- data/spec/mongo/server/connection_auth_spec.rb +2 -2
- data/spec/mongo/server/connection_pool_spec.rb +7 -3
- data/spec/mongo/server/connection_spec.rb +15 -8
- data/spec/mongo/server/description_spec.rb +18 -0
- data/spec/mongo/server_selector/nearest_spec.rb +23 -23
- data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
- data/spec/mongo/server_selector/primary_spec.rb +9 -9
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
- data/spec/mongo/server_selector/secondary_spec.rb +18 -18
- data/spec/mongo/server_selector_spec.rb +6 -6
- data/spec/mongo/session_spec.rb +35 -0
- data/spec/mongo/socket/ssl_spec.rb +4 -4
- data/spec/mongo/socket_spec.rb +1 -1
- data/spec/mongo/uri/srv_protocol_spec.rb +64 -33
- data/spec/mongo/uri_option_parsing_spec.rb +11 -11
- data/spec/mongo/uri_spec.rb +68 -41
- data/spec/mongo/utils_spec.rb +39 -0
- data/spec/runners/auth.rb +3 -0
- data/spec/runners/change_streams/test.rb +3 -3
- data/spec/runners/cmap.rb +1 -1
- data/spec/runners/command_monitoring.rb +3 -34
- data/spec/runners/connection_string.rb +35 -124
- data/spec/runners/crud/context.rb +9 -5
- data/spec/runners/crud/operation.rb +59 -27
- data/spec/runners/crud/spec.rb +0 -8
- data/spec/runners/crud/test.rb +1 -1
- data/spec/runners/crud/test_base.rb +0 -19
- data/spec/runners/sdam.rb +2 -2
- data/spec/runners/server_selection.rb +242 -28
- data/spec/runners/transactions.rb +12 -12
- data/spec/runners/transactions/operation.rb +151 -25
- data/spec/runners/transactions/test.rb +62 -18
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/constraints.rb +303 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/spec_tests/cmap_spec.rb +7 -3
- data/spec/spec_tests/command_monitoring_spec.rb +22 -12
- data/spec/spec_tests/crud_spec.rb +1 -1
- data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -9
- data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
- data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
- data/spec/spec_tests/data/cmap/pool-checkout-connection.yml +6 -2
- data/spec/spec_tests/data/cmap/pool-create-min-size.yml +3 -0
- data/spec/spec_tests/data/connection_string/valid-warnings.yml +24 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
- data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
- data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
- data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
- data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
- data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
- data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
- data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
- data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
- data/spec/spec_tests/data/sdam_monitoring/discovered_standalone.yml +1 -3
- data/spec/spec_tests/data/sdam_monitoring/standalone.yml +2 -2
- data/spec/spec_tests/data/sdam_monitoring/standalone_repeated.yml +2 -2
- data/spec/spec_tests/data/sdam_monitoring/standalone_suppress_equal_description_changes.yml +2 -2
- data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +2 -2
- data/spec/spec_tests/data/uri_options/auth-options.yml +25 -0
- data/spec/spec_tests/data/uri_options/compression-options.yml +6 -3
- data/spec/spec_tests/data/uri_options/read-preference-options.yml +24 -0
- data/spec/spec_tests/data/uri_options/ruby-connection-options.yml +1 -0
- data/spec/spec_tests/data/uri_options/tls-options.yml +160 -4
- data/spec/spec_tests/dns_seedlist_discovery_spec.rb +9 -1
- data/spec/spec_tests/max_staleness_spec.rb +4 -142
- data/spec/spec_tests/retryable_reads_spec.rb +2 -2
- data/spec/spec_tests/sdam_integration_spec.rb +13 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
- data/spec/spec_tests/server_selection_spec.rb +4 -116
- data/spec/spec_tests/uri_options_spec.rb +31 -33
- data/spec/stress/cleanup_spec.rb +17 -2
- data/spec/stress/connection_pool_stress_spec.rb +10 -8
- data/spec/stress/fork_reconnect_stress_spec.rb +1 -1
- data/spec/support/certificates/atlas-ocsp-ca.crt +28 -0
- data/spec/support/certificates/atlas-ocsp.crt +41 -0
- data/spec/support/client_registry.rb +1 -0
- data/spec/support/client_registry_macros.rb +11 -2
- data/spec/support/cluster_config.rb +4 -0
- data/spec/support/common_shortcuts.rb +45 -0
- data/spec/support/constraints.rb +6 -253
- data/spec/support/event_subscriber.rb +123 -33
- data/spec/support/keyword_struct.rb +26 -0
- data/spec/support/matchers.rb +16 -0
- data/spec/support/ocsp +1 -0
- data/spec/support/session_registry.rb +52 -0
- data/spec/support/shared/server_selector.rb +13 -1
- data/spec/support/spec_config.rb +60 -13
- data/spec/support/spec_setup.rb +1 -1
- data/spec/support/utils.rb +84 -1
- metadata +1027 -937
- metadata.gz.sig +0 -0
- data/lib/mongo/server_selector/selectable.rb +0 -560
- data/spec/runners/sdam_monitoring.rb +0 -89
- data/spec/support/lite_constraints.rb +0 -141
@@ -0,0 +1,1045 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'QueryCache' do
|
4
|
+
around do |spec|
|
5
|
+
Mongo::QueryCache.clear
|
6
|
+
Mongo::QueryCache.cache { spec.run }
|
7
|
+
end
|
8
|
+
|
9
|
+
before do
|
10
|
+
authorized_collection.delete_many
|
11
|
+
subscriber.clear_events!
|
12
|
+
end
|
13
|
+
|
14
|
+
before(:all) do
|
15
|
+
# It is likely that there are other session leaks in the driver that are
|
16
|
+
# unrelated to the query cache. Clear the SessionRegistry at the start of
|
17
|
+
# these tests in order to detect leaks that occur only within the scope of
|
18
|
+
# these tests.
|
19
|
+
#
|
20
|
+
# Other session leaks will be detected and addressed as part of RUBY-2391.
|
21
|
+
SessionRegistry.instance.clear_registry
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
SessionRegistry.instance.verify_sessions_ended!
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:subscriber) { EventSubscriber.new }
|
29
|
+
|
30
|
+
let(:client) do
|
31
|
+
authorized_client.tap do |client|
|
32
|
+
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:authorized_collection) { client['collection_spec'] }
|
37
|
+
|
38
|
+
let(:events) do
|
39
|
+
subscriber.command_started_events('find')
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#cache' do
|
43
|
+
|
44
|
+
before do
|
45
|
+
Mongo::QueryCache.enabled = false
|
46
|
+
authorized_collection.insert_one({ name: 'testing' })
|
47
|
+
authorized_collection.find(name: 'testing').to_a
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'enables the query cache inside the block' do
|
51
|
+
Mongo::QueryCache.cache do
|
52
|
+
authorized_collection.find(name: 'testing').to_a
|
53
|
+
expect(Mongo::QueryCache.enabled?).to be(true)
|
54
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
55
|
+
expect(events.length).to eq(2)
|
56
|
+
end
|
57
|
+
authorized_collection.find(name: 'testing').to_a
|
58
|
+
expect(Mongo::QueryCache.enabled?).to be(false)
|
59
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
60
|
+
expect(events.length).to eq(2)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#uncached' do
|
65
|
+
|
66
|
+
before do
|
67
|
+
authorized_collection.insert_one({ name: 'testing' })
|
68
|
+
authorized_collection.find(name: 'testing').to_a
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'disables the query cache inside the block' do
|
72
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
73
|
+
Mongo::QueryCache.uncached do
|
74
|
+
authorized_collection.find(name: 'testing').to_a
|
75
|
+
expect(Mongo::QueryCache.enabled?).to be(false)
|
76
|
+
expect(events.length).to eq(2)
|
77
|
+
end
|
78
|
+
authorized_collection.find(name: 'testing').to_a
|
79
|
+
expect(Mongo::QueryCache.enabled?).to be(true)
|
80
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
81
|
+
expect(events.length).to eq(2)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'query with multiple batches' do
|
86
|
+
min_server_fcv '3.2'
|
87
|
+
|
88
|
+
before do
|
89
|
+
102.times { |i| authorized_collection.insert_one(_id: i) }
|
90
|
+
end
|
91
|
+
|
92
|
+
let(:expected_results) { [*0..101].map { |id| { "_id" => id } } }
|
93
|
+
|
94
|
+
it 'returns the correct result' do
|
95
|
+
result = authorized_collection.find.to_a
|
96
|
+
expect(result.length).to eq(102)
|
97
|
+
expect(result).to eq(expected_results)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns the correct result multiple times' do
|
101
|
+
result1 = authorized_collection.find.to_a
|
102
|
+
result2 = authorized_collection.find.to_a
|
103
|
+
expect(result1).to eq(expected_results)
|
104
|
+
expect(result2).to eq(expected_results)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'caches the query' do
|
108
|
+
authorized_collection.find.to_a
|
109
|
+
authorized_collection.find.to_a
|
110
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
111
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'uses cached cursor when limited' do
|
115
|
+
authorized_collection.find.to_a
|
116
|
+
result = authorized_collection.find({}, limit: 5).to_a
|
117
|
+
|
118
|
+
expect(result.length).to eq(5)
|
119
|
+
expect(result).to eq(expected_results.first(5))
|
120
|
+
|
121
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
122
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'can be used with a block API' do
|
126
|
+
authorized_collection.find.to_a
|
127
|
+
|
128
|
+
result = []
|
129
|
+
authorized_collection.find.each do |doc|
|
130
|
+
result << doc
|
131
|
+
end
|
132
|
+
|
133
|
+
expect(result).to eq(expected_results)
|
134
|
+
|
135
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
136
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when the cursor isn\'t fully iterated the first time' do
|
140
|
+
it 'continues iterating' do
|
141
|
+
result1 = authorized_collection.find.first(5)
|
142
|
+
|
143
|
+
expect(result1.length).to eq(5)
|
144
|
+
expect(result1).to eq(expected_results.first(5))
|
145
|
+
|
146
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
147
|
+
expect(subscriber.command_started_events('getMore').length).to eq(0)
|
148
|
+
|
149
|
+
result2 = authorized_collection.find.to_a
|
150
|
+
|
151
|
+
expect(result2.length).to eq(102)
|
152
|
+
expect(result2).to eq(expected_results)
|
153
|
+
|
154
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
155
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'can be iterated multiple times' do
|
159
|
+
authorized_collection.find.first(5)
|
160
|
+
authorized_collection.find.to_a
|
161
|
+
|
162
|
+
result = authorized_collection.find.to_a
|
163
|
+
|
164
|
+
expect(result.length).to eq(102)
|
165
|
+
expect(result).to eq(expected_results)
|
166
|
+
|
167
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
168
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'can be used with a block API' do
|
172
|
+
authorized_collection.find.first(5)
|
173
|
+
|
174
|
+
result = []
|
175
|
+
authorized_collection.find.each do |doc|
|
176
|
+
result << doc
|
177
|
+
end
|
178
|
+
|
179
|
+
expect(result.length).to eq(102)
|
180
|
+
expect(result).to eq(expected_results)
|
181
|
+
|
182
|
+
expect(subscriber.command_started_events('find').length).to eq(1)
|
183
|
+
expect(subscriber.command_started_events('getMore').length).to eq(1)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe 'queries with read concern' do
|
189
|
+
require_wired_tiger
|
190
|
+
min_server_fcv '3.6'
|
191
|
+
|
192
|
+
before do
|
193
|
+
authorized_client['test'].drop
|
194
|
+
end
|
195
|
+
|
196
|
+
context 'when two queries have same read concern' do
|
197
|
+
before do
|
198
|
+
authorized_client['test', read_concern: { level: :majority }].find.to_a
|
199
|
+
authorized_client['test', read_concern: { level: :majority }].find.to_a
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'executes one query' do
|
203
|
+
expect(events.length).to eq(1)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when two queries have different read concerns' do
|
208
|
+
before do
|
209
|
+
authorized_client['test', read_concern: { level: :majority }].find.to_a
|
210
|
+
authorized_client['test', read_concern: { level: :local }].find.to_a
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'executes two queries' do
|
214
|
+
expect(events.length).to eq(2)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe 'queries with read preference' do
|
220
|
+
before do
|
221
|
+
subscriber.clear_events!
|
222
|
+
authorized_client['test'].drop
|
223
|
+
end
|
224
|
+
|
225
|
+
context 'when two queries have different read preferences' do
|
226
|
+
before do
|
227
|
+
authorized_client['test', read: { mode: :primary }].find.to_a
|
228
|
+
authorized_client['test', read: { mode: :primary_preferred }].find.to_a
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'executes two queries' do
|
232
|
+
expect(events.length).to eq(2)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'when two queries have same read preference' do
|
237
|
+
before do
|
238
|
+
authorized_client['test', read: { mode: :primary }].find.to_a
|
239
|
+
authorized_client['test', read: { mode: :primary }].find.to_a
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'executes one query' do
|
243
|
+
expect(events.length).to eq(1)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe 'query fills up entire batch' do
|
249
|
+
before do
|
250
|
+
subscriber.clear_events!
|
251
|
+
authorized_client['test'].drop
|
252
|
+
|
253
|
+
2.times { |i| authorized_client['test'].insert_one(_id: i) }
|
254
|
+
end
|
255
|
+
|
256
|
+
let(:expected_result) do
|
257
|
+
[{ "_id" => 0 }, { "_id" => 1 }]
|
258
|
+
end
|
259
|
+
|
260
|
+
# When the last batch runs out, try_next will return nil instead of a
|
261
|
+
# document. This test checks that nil is not added to the list of cached
|
262
|
+
# documents or returned as a result.
|
263
|
+
it 'returns the correct response' do
|
264
|
+
expect(authorized_client['test'].find({}, batch_size: 2).to_a).to eq(expected_result)
|
265
|
+
expect(authorized_client['test'].find({}, batch_size: 2).to_a).to eq(expected_result)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
context 'when querying in the same collection' do
|
270
|
+
|
271
|
+
before do
|
272
|
+
10.times do |i|
|
273
|
+
authorized_collection.insert_one(test: i)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'when query cache is disabled' do
|
278
|
+
|
279
|
+
before do
|
280
|
+
Mongo::QueryCache.enabled = false
|
281
|
+
authorized_collection.find(test: 1).to_a
|
282
|
+
end
|
283
|
+
|
284
|
+
it 'queries again' do
|
285
|
+
authorized_collection.find(test: 1).to_a
|
286
|
+
expect(events.length).to eq(2)
|
287
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(0)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'when query cache is enabled' do
|
292
|
+
|
293
|
+
before do
|
294
|
+
authorized_collection.find(test: 1).to_a
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'does not query again' do
|
298
|
+
authorized_collection.find(test: 1).to_a
|
299
|
+
expect(events.length).to eq(1)
|
300
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'when query has collation' do
|
305
|
+
min_server_fcv '3.4'
|
306
|
+
|
307
|
+
let(:options1) do
|
308
|
+
{ :collation => { locale: 'fr' } }
|
309
|
+
end
|
310
|
+
|
311
|
+
let(:options2) do
|
312
|
+
{ collation: { locale: 'en_US' } }
|
313
|
+
end
|
314
|
+
|
315
|
+
before do
|
316
|
+
authorized_collection.find({ test: 3 }, options1).to_a
|
317
|
+
end
|
318
|
+
|
319
|
+
context 'when query has the same collation' do
|
320
|
+
|
321
|
+
it 'uses the cache' do
|
322
|
+
authorized_collection.find({ test: 3 }, options1).to_a
|
323
|
+
expect(events.length).to eq(1)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
context 'when query has a different collation' do
|
328
|
+
|
329
|
+
it 'queries again' do
|
330
|
+
authorized_collection.find({ test: 3 }, options2).to_a
|
331
|
+
expect(events.length).to eq(2)
|
332
|
+
expect(Mongo::QueryCache.send(:cache_table)['ruby-driver.collection_spec'].length).to eq(2)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe 'queries with limits' do
|
338
|
+
context 'when the first query has no limit and the second does' do
|
339
|
+
before do
|
340
|
+
authorized_collection.find.to_a.count
|
341
|
+
end
|
342
|
+
|
343
|
+
it 'uses the cache' do
|
344
|
+
results_limit_5 = authorized_collection.find.limit(5).to_a
|
345
|
+
results_limit_3 = authorized_collection.find.limit(3).to_a
|
346
|
+
results_no_limit = authorized_collection.find.to_a
|
347
|
+
|
348
|
+
expect(results_limit_5.length).to eq(5)
|
349
|
+
expect(results_limit_5.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4])
|
350
|
+
|
351
|
+
expect(results_limit_3.length).to eq(3)
|
352
|
+
expect(results_limit_3.map { |r| r["test"] }).to eq([0, 1, 2])
|
353
|
+
|
354
|
+
expect(results_no_limit.length).to eq(10)
|
355
|
+
expect(results_no_limit.map { |r| r["test"] }).to eq([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
356
|
+
|
357
|
+
expect(events.length).to eq(1)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
context 'when the first query has a limit' do
|
362
|
+
before do
|
363
|
+
authorized_collection.find.limit(2).to_a
|
364
|
+
end
|
365
|
+
|
366
|
+
context 'and the second query has a larger limit' do
|
367
|
+
let(:results) { authorized_collection.find.limit(3).to_a }
|
368
|
+
|
369
|
+
it 'queries again' do
|
370
|
+
expect(results.length).to eq(3)
|
371
|
+
expect(results.map { |result| result["test"] }).to eq([0, 1, 2])
|
372
|
+
expect(events.length).to eq(2)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
context 'and two queries are performed with a larger limit' do
|
377
|
+
it 'uses the query cache for the third query' do
|
378
|
+
results1 = authorized_collection.find.limit(3).to_a
|
379
|
+
results2 = authorized_collection.find.limit(3).to_a
|
380
|
+
|
381
|
+
expect(results1.length).to eq(3)
|
382
|
+
expect(results1.map { |r| r["test"] }).to eq([0, 1, 2])
|
383
|
+
|
384
|
+
expect(results2.length).to eq(3)
|
385
|
+
expect(results2.map { |r| r["test"] }).to eq([0, 1, 2])
|
386
|
+
|
387
|
+
expect(events.length).to eq(2)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
context 'and the second query has a smaller limit' do
|
392
|
+
let(:results) { authorized_collection.find.limit(1).to_a }
|
393
|
+
|
394
|
+
it 'uses the cached query' do
|
395
|
+
expect(results.count).to eq(1)
|
396
|
+
expect(results.first["test"]).to eq(0)
|
397
|
+
expect(events.length).to eq(1)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
context 'and the second query has no limit' do
|
402
|
+
it 'queries again' do
|
403
|
+
expect(authorized_collection.find.to_a.count).to eq(10)
|
404
|
+
expect(events.length).to eq(2)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
context 'when querying only the first' do
|
411
|
+
|
412
|
+
before do
|
413
|
+
5.times do |i|
|
414
|
+
authorized_collection.insert_one(test: 11)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
before do
|
419
|
+
authorized_collection.find({test: 11}).to_a
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'does not query again' do
|
423
|
+
expect(authorized_collection.find({test: 11}).count).to eq(5)
|
424
|
+
authorized_collection.find({test: 11}).first
|
425
|
+
expect(events.length).to eq(1)
|
426
|
+
end
|
427
|
+
|
428
|
+
context 'when limiting the result' do
|
429
|
+
|
430
|
+
it 'does not query again' do
|
431
|
+
authorized_collection.find({test: 11}, limit: 2).to_a
|
432
|
+
expect(authorized_collection.find({test: 11}, limit: 2).to_a.count).to eq(2)
|
433
|
+
expect(events.length).to eq(1)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
context 'when specifying a different skip value' do
|
439
|
+
|
440
|
+
before do
|
441
|
+
authorized_collection.find({}, {limit: 2, skip: 3}).to_a
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'queries again' do
|
445
|
+
results = authorized_collection.find({}, {limit: 2, skip: 5}).to_a
|
446
|
+
expect(results.count).to eq(2)
|
447
|
+
expect(events.length).to eq(2)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
context 'when sorting documents' do
|
452
|
+
|
453
|
+
before do
|
454
|
+
authorized_collection.find({}, desc).to_a
|
455
|
+
end
|
456
|
+
|
457
|
+
let(:desc) do
|
458
|
+
{ sort: {test: -1} }
|
459
|
+
end
|
460
|
+
|
461
|
+
let(:asc) do
|
462
|
+
{ sort: {test: 1} }
|
463
|
+
end
|
464
|
+
|
465
|
+
context 'with different selector' do
|
466
|
+
|
467
|
+
it 'queries again' do
|
468
|
+
authorized_collection.find({}, asc).to_a
|
469
|
+
expect(events.length).to eq(2)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'does not query again' do
|
474
|
+
authorized_collection.find({}, desc).to_a
|
475
|
+
expect(events.length).to eq(1)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
context 'when inserting new documents' do
|
480
|
+
context 'when inserting and querying from same collection' do
|
481
|
+
before do
|
482
|
+
authorized_collection.find.to_a
|
483
|
+
authorized_collection.insert_one({ name: "bob" })
|
484
|
+
end
|
485
|
+
|
486
|
+
it 'queries again' do
|
487
|
+
authorized_collection.find.to_a
|
488
|
+
expect(events.length).to eq(2)
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
context 'when inserting and querying from different collections' do
|
493
|
+
before do
|
494
|
+
authorized_collection.find.to_a
|
495
|
+
authorized_client['different_collection'].insert_one({ name: "bob" })
|
496
|
+
end
|
497
|
+
|
498
|
+
it 'uses the cached query' do
|
499
|
+
authorized_collection.find.to_a
|
500
|
+
expect(events.length).to eq(1)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
[:delete_many, :delete_one].each do |method|
|
506
|
+
context "when deleting with #{method}" do
|
507
|
+
context 'when deleting and querying from same collection' do
|
508
|
+
before do
|
509
|
+
authorized_collection.find.to_a
|
510
|
+
authorized_collection.send(method)
|
511
|
+
end
|
512
|
+
|
513
|
+
it 'queries again' do
|
514
|
+
authorized_collection.find.to_a
|
515
|
+
expect(events.length).to eq(2)
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
context 'when deleting and querying from different collections' do
|
520
|
+
before do
|
521
|
+
authorized_collection.find.to_a
|
522
|
+
authorized_client['different_collection'].send(method)
|
523
|
+
end
|
524
|
+
|
525
|
+
it 'uses the cached query' do
|
526
|
+
authorized_collection.find.to_a
|
527
|
+
expect(events.length).to eq(1)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
[:find_one_and_delete, :find_one_and_replace, :find_one_and_update,
|
534
|
+
:update_one, :replace_one].each do |method|
|
535
|
+
context "when updating with #{method}" do
|
536
|
+
context 'when updating and querying from same collection' do
|
537
|
+
before do
|
538
|
+
authorized_collection.find.to_a
|
539
|
+
authorized_collection.send(method, { field: 'value' }, { field: 'new value' })
|
540
|
+
end
|
541
|
+
|
542
|
+
it 'queries again' do
|
543
|
+
authorized_collection.find.to_a
|
544
|
+
expect(events.length).to eq(2)
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
context 'when updating and querying from different collections' do
|
549
|
+
before do
|
550
|
+
authorized_collection.find.to_a
|
551
|
+
authorized_client['different_collection'].send(method, { field: 'value' }, { field: 'new value' })
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'uses the cached query' do
|
555
|
+
authorized_collection.find.to_a
|
556
|
+
expect(events.length).to eq(1)
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
562
|
+
context 'when updating with #update_many' do
|
563
|
+
context 'when updating and querying from same collection' do
|
564
|
+
before do
|
565
|
+
authorized_collection.find.to_a
|
566
|
+
authorized_collection.update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
|
567
|
+
end
|
568
|
+
|
569
|
+
it 'queries again' do
|
570
|
+
authorized_collection.find.to_a
|
571
|
+
expect(events.length).to eq(2)
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
context 'when updating and querying from different collections' do
|
576
|
+
before do
|
577
|
+
authorized_collection.find.to_a
|
578
|
+
authorized_client['different_collection'].update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
|
579
|
+
end
|
580
|
+
|
581
|
+
it 'uses the cached query' do
|
582
|
+
authorized_collection.find.to_a
|
583
|
+
expect(events.length).to eq(1)
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
context 'when performing bulk write' do
|
589
|
+
context 'with insert_one' do
|
590
|
+
context 'when inserting and querying from same collection' do
|
591
|
+
before do
|
592
|
+
authorized_collection.find.to_a
|
593
|
+
authorized_collection.bulk_write([ { insert_one: { name: 'bob' } } ])
|
594
|
+
end
|
595
|
+
|
596
|
+
it 'queries again' do
|
597
|
+
authorized_collection.find.to_a
|
598
|
+
expect(events.length).to eq(2)
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
context 'when inserting and querying from different collection' do
|
603
|
+
before do
|
604
|
+
authorized_collection.find.to_a
|
605
|
+
authorized_client['different_collection'].bulk_write(
|
606
|
+
[ { insert_one: { name: 'bob' } } ]
|
607
|
+
)
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'uses the cached query' do
|
611
|
+
authorized_collection.find.to_a
|
612
|
+
expect(events.length).to eq(1)
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
[:update_one, :update_many].each do |method|
|
618
|
+
context "with #{method}" do
|
619
|
+
context 'when updating and querying from same collection' do
|
620
|
+
before do
|
621
|
+
authorized_collection.find.to_a
|
622
|
+
authorized_collection.bulk_write([
|
623
|
+
{
|
624
|
+
method => {
|
625
|
+
filter: { field: 'value' },
|
626
|
+
update: { '$set' => { field: 'new value' } }
|
627
|
+
}
|
628
|
+
}
|
629
|
+
])
|
630
|
+
end
|
631
|
+
|
632
|
+
it 'queries again' do
|
633
|
+
authorized_collection.find.to_a
|
634
|
+
expect(events.length).to eq(2)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'when updating and querying from different collection' do
|
639
|
+
before do
|
640
|
+
authorized_collection.find.to_a
|
641
|
+
authorized_client['different_collection'].bulk_write([
|
642
|
+
{
|
643
|
+
method => {
|
644
|
+
filter: { field: 'value' },
|
645
|
+
update: { '$set' => { field: 'new value' } }
|
646
|
+
}
|
647
|
+
}
|
648
|
+
])
|
649
|
+
end
|
650
|
+
|
651
|
+
it 'uses the cached query' do
|
652
|
+
authorized_collection.find.to_a
|
653
|
+
expect(events.length).to eq(1)
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
[:delete_one, :delete_many].each do |method|
|
660
|
+
context "with #{method}" do
|
661
|
+
context 'when delete and querying from same collection' do
|
662
|
+
before do
|
663
|
+
authorized_collection.find.to_a
|
664
|
+
authorized_collection.bulk_write([
|
665
|
+
{
|
666
|
+
method => {
|
667
|
+
filter: { field: 'value' },
|
668
|
+
}
|
669
|
+
}
|
670
|
+
])
|
671
|
+
end
|
672
|
+
|
673
|
+
it 'queries again' do
|
674
|
+
authorized_collection.find.to_a
|
675
|
+
expect(events.length).to eq(2)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
context 'when delete and querying from different collection' do
|
680
|
+
before do
|
681
|
+
authorized_collection.find.to_a
|
682
|
+
authorized_client['different_collection'].bulk_write([
|
683
|
+
{
|
684
|
+
method => {
|
685
|
+
filter: { field: 'value' },
|
686
|
+
}
|
687
|
+
}
|
688
|
+
])
|
689
|
+
end
|
690
|
+
|
691
|
+
it 'uses the cached query' do
|
692
|
+
authorized_collection.find.to_a
|
693
|
+
expect(events.length).to eq(1)
|
694
|
+
end
|
695
|
+
end
|
696
|
+
end
|
697
|
+
end
|
698
|
+
|
699
|
+
context 'with replace_one' do
|
700
|
+
context 'when replacing and querying from same collection' do
|
701
|
+
before do
|
702
|
+
authorized_collection.find.to_a
|
703
|
+
authorized_collection.bulk_write([
|
704
|
+
{
|
705
|
+
replace_one: {
|
706
|
+
filter: { field: 'value' },
|
707
|
+
replacement: { field: 'new value' }
|
708
|
+
}
|
709
|
+
}
|
710
|
+
])
|
711
|
+
end
|
712
|
+
|
713
|
+
it 'queries again' do
|
714
|
+
authorized_collection.find.to_a
|
715
|
+
expect(events.length).to eq(2)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
context 'when replacing and querying from different collection' do
|
720
|
+
before do
|
721
|
+
authorized_collection.find.to_a
|
722
|
+
authorized_client['different_collection'].bulk_write([
|
723
|
+
{
|
724
|
+
replace_one: {
|
725
|
+
filter: { field: 'value' },
|
726
|
+
replacement: { field: 'new value' }
|
727
|
+
}
|
728
|
+
}
|
729
|
+
])
|
730
|
+
end
|
731
|
+
|
732
|
+
it 'uses the cached query' do
|
733
|
+
authorized_collection.find.to_a
|
734
|
+
expect(events.length).to eq(1)
|
735
|
+
end
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
context 'when query occurs between bulk write creation and execution' do
|
740
|
+
before do
|
741
|
+
authorized_collection.delete_many
|
742
|
+
end
|
743
|
+
|
744
|
+
it 'queries again' do
|
745
|
+
bulk_write = Mongo::BulkWrite.new(
|
746
|
+
authorized_collection,
|
747
|
+
[{ insert_one: { test: 1 } }]
|
748
|
+
)
|
749
|
+
|
750
|
+
expect(authorized_collection.find(test: 1).to_a.length).to eq(0)
|
751
|
+
bulk_write.execute
|
752
|
+
expect(authorized_collection.find(test: 1).to_a.length).to eq(1)
|
753
|
+
expect(events.length).to eq(2)
|
754
|
+
end
|
755
|
+
end
|
756
|
+
end
|
757
|
+
|
758
|
+
context 'when aggregating with $out' do
|
759
|
+
before do
|
760
|
+
authorized_collection.find.to_a
|
761
|
+
authorized_collection.aggregate([
|
762
|
+
{ '$match' => { test: 1 } },
|
763
|
+
{ '$out' => { coll: 'new_coll' } }
|
764
|
+
])
|
765
|
+
end
|
766
|
+
|
767
|
+
it 'queries again' do
|
768
|
+
authorized_collection.find.to_a
|
769
|
+
expect(events.length).to eq(2)
|
770
|
+
end
|
771
|
+
|
772
|
+
it 'clears the cache' do
|
773
|
+
expect(Mongo::QueryCache.send(:cache_table)).to be_empty
|
774
|
+
end
|
775
|
+
end
|
776
|
+
|
777
|
+
context 'when aggregating with $merge' do
|
778
|
+
min_server_fcv '4.2'
|
779
|
+
|
780
|
+
before do
|
781
|
+
authorized_collection.delete_many
|
782
|
+
authorized_collection.find.to_a
|
783
|
+
authorized_collection.aggregate([
|
784
|
+
{ '$match' => { 'test' => 1 } },
|
785
|
+
{ '$merge' => {
|
786
|
+
into: {
|
787
|
+
db: SpecConfig.instance.test_db,
|
788
|
+
coll: 'new_coll',
|
789
|
+
},
|
790
|
+
on: "_id",
|
791
|
+
whenMatched: "replace",
|
792
|
+
whenNotMatched: "insert",
|
793
|
+
}
|
794
|
+
}
|
795
|
+
])
|
796
|
+
end
|
797
|
+
|
798
|
+
it 'queries again' do
|
799
|
+
authorized_collection.find.to_a
|
800
|
+
expect(events.length).to eq(2)
|
801
|
+
end
|
802
|
+
|
803
|
+
it 'clears the cache' do
|
804
|
+
expect(Mongo::QueryCache.send(:cache_table)).to be_empty
|
805
|
+
end
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
context 'when aggregating' do
|
810
|
+
before do
|
811
|
+
3.times { authorized_collection.insert_one(test: 1) }
|
812
|
+
end
|
813
|
+
|
814
|
+
let(:events) do
|
815
|
+
subscriber.command_started_events('aggregate')
|
816
|
+
end
|
817
|
+
|
818
|
+
let(:aggregation) do
|
819
|
+
authorized_collection.aggregate([ { '$match' => { test: 1 } } ])
|
820
|
+
end
|
821
|
+
|
822
|
+
it 'caches the aggregation' do
|
823
|
+
expect(aggregation.to_a.length).to eq(3)
|
824
|
+
expect(aggregation.to_a.length).to eq(3)
|
825
|
+
expect(events.length).to eq(1)
|
826
|
+
end
|
827
|
+
|
828
|
+
context 'with read concern' do
|
829
|
+
require_wired_tiger
|
830
|
+
min_server_fcv '3.6'
|
831
|
+
|
832
|
+
let(:aggregation_read_concern) do
|
833
|
+
authorized_client['collection_spec', { read_concern: { level: :local } }]
|
834
|
+
.aggregate([ { '$match' => { test: 1 } } ])
|
835
|
+
end
|
836
|
+
|
837
|
+
it 'queries twice' do
|
838
|
+
expect(aggregation.to_a.length).to eq(3)
|
839
|
+
expect(aggregation_read_concern.to_a.length).to eq(3)
|
840
|
+
expect(events.length).to eq(2)
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
context 'with read preference' do
|
845
|
+
let(:aggregation_read_preference) do
|
846
|
+
authorized_client['collection_spec', { read: { mode: :primary } }]
|
847
|
+
.aggregate([ { '$match' => { test: 1 } } ])
|
848
|
+
end
|
849
|
+
|
850
|
+
it 'queries twice' do
|
851
|
+
expect(aggregation.to_a.length).to eq(3)
|
852
|
+
expect(aggregation_read_preference.to_a.length).to eq(3)
|
853
|
+
expect(events.length).to eq(2)
|
854
|
+
end
|
855
|
+
end
|
856
|
+
|
857
|
+
context 'when collation is specified' do
|
858
|
+
min_server_fcv '3.4'
|
859
|
+
|
860
|
+
let(:aggregation_collation) do
|
861
|
+
authorized_collection.aggregate(
|
862
|
+
[ { '$match' => { test: 1 } } ],
|
863
|
+
{ collation: { locale: 'fr' } }
|
864
|
+
)
|
865
|
+
end
|
866
|
+
|
867
|
+
it 'queries twice' do
|
868
|
+
expect(aggregation.to_a.length).to eq(3)
|
869
|
+
expect(aggregation_collation.to_a.length).to eq(3)
|
870
|
+
expect(events.length).to eq(2)
|
871
|
+
end
|
872
|
+
end
|
873
|
+
|
874
|
+
context 'when insert_one is performed on another collection' do
|
875
|
+
before do
|
876
|
+
aggregation.to_a
|
877
|
+
authorized_client['different_collection'].insert_one(name: 'bob')
|
878
|
+
aggregation.to_a
|
879
|
+
end
|
880
|
+
|
881
|
+
it 'queries again' do
|
882
|
+
expect(events.length).to eq(2)
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
context 'when insert_many is performed on another collection' do
|
887
|
+
before do
|
888
|
+
aggregation.to_a
|
889
|
+
authorized_client['different_collection'].insert_many([name: 'bob'])
|
890
|
+
aggregation.to_a
|
891
|
+
end
|
892
|
+
|
893
|
+
it 'queries again' do
|
894
|
+
expect(events.length).to eq(2)
|
895
|
+
end
|
896
|
+
end
|
897
|
+
|
898
|
+
[:delete_many, :delete_one].each do |method|
|
899
|
+
context "when #{method} is performed on another collection" do
|
900
|
+
before do
|
901
|
+
aggregation.to_a
|
902
|
+
authorized_client['different_collection'].send(method)
|
903
|
+
aggregation.to_a
|
904
|
+
end
|
905
|
+
|
906
|
+
it 'queries again' do
|
907
|
+
expect(events.length).to eq(2)
|
908
|
+
end
|
909
|
+
end
|
910
|
+
end
|
911
|
+
|
912
|
+
[:find_one_and_delete, :find_one_and_replace, :find_one_and_update,
|
913
|
+
:update_one, :replace_one].each do |method|
|
914
|
+
context "when #{method} is performed on another collection" do
|
915
|
+
before do
|
916
|
+
aggregation.to_a
|
917
|
+
authorized_client['different_collection'].send(method, { field: 'value' }, { field: 'new value' })
|
918
|
+
aggregation.to_a
|
919
|
+
end
|
920
|
+
|
921
|
+
it 'queries again' do
|
922
|
+
expect(events.length).to eq(2)
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
|
927
|
+
context 'when update_many is performed on another collection' do
|
928
|
+
before do
|
929
|
+
aggregation.to_a
|
930
|
+
authorized_client['different_collection'].update_many({ field: 'value' }, { "$inc" => { :field => 1 } })
|
931
|
+
aggregation.to_a
|
932
|
+
end
|
933
|
+
|
934
|
+
it 'queries again' do
|
935
|
+
expect(events.length).to eq(2)
|
936
|
+
end
|
937
|
+
end
|
938
|
+
|
939
|
+
context '#count_documents' do
|
940
|
+
context 'on same collection' do
|
941
|
+
it 'caches the query' do
|
942
|
+
expect(authorized_collection.count_documents(test: 1)).to eq(3)
|
943
|
+
expect(authorized_collection.count_documents(test: 1)).to eq(3)
|
944
|
+
|
945
|
+
expect(events.length).to eq(1)
|
946
|
+
end
|
947
|
+
end
|
948
|
+
|
949
|
+
context 'on different collections' do
|
950
|
+
let(:other_collection) { authorized_client['other_collection'] }
|
951
|
+
|
952
|
+
before do
|
953
|
+
other_collection.drop
|
954
|
+
6.times { other_collection.insert_one(test: 1) }
|
955
|
+
end
|
956
|
+
|
957
|
+
it 'caches the query' do
|
958
|
+
expect(authorized_collection.count_documents(test: 1)).to eq(3)
|
959
|
+
expect(other_collection.count_documents(test: 1)).to eq(6)
|
960
|
+
|
961
|
+
expect(events.length).to eq(2)
|
962
|
+
end
|
963
|
+
end
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
context 'when find command fails and retries' do
|
968
|
+
require_fail_command
|
969
|
+
require_no_multi_shard
|
970
|
+
require_warning_clean
|
971
|
+
|
972
|
+
before do
|
973
|
+
5.times do |i|
|
974
|
+
authorized_collection.insert_one(test: i)
|
975
|
+
end
|
976
|
+
end
|
977
|
+
|
978
|
+
before do
|
979
|
+
client.use('admin').command(
|
980
|
+
configureFailPoint: 'failCommand',
|
981
|
+
mode: { times: 1 },
|
982
|
+
data: {
|
983
|
+
failCommands: ['find'],
|
984
|
+
closeConnection: true
|
985
|
+
}
|
986
|
+
)
|
987
|
+
end
|
988
|
+
|
989
|
+
let(:command_name) { 'find' }
|
990
|
+
|
991
|
+
it 'uses modern retryable reads when using query cache' do
|
992
|
+
expect(Mongo::QueryCache.enabled?).to be(true)
|
993
|
+
|
994
|
+
expect(Mongo::Logger.logger).to receive(:warn).once.with(/modern.*attempt 1/).and_call_original
|
995
|
+
authorized_collection.find(test: 1).to_a
|
996
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
997
|
+
expect(subscriber.command_started_events('find').length).to eq(2)
|
998
|
+
|
999
|
+
authorized_collection.find(test: 1).to_a
|
1000
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(1)
|
1001
|
+
expect(subscriber.command_started_events('find').length).to eq(2)
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
context 'when querying in a different collection' do
|
1006
|
+
|
1007
|
+
let(:database) { client.database }
|
1008
|
+
|
1009
|
+
let(:new_collection) do
|
1010
|
+
Mongo::Collection.new(database, 'foo')
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
before do
|
1014
|
+
authorized_collection.find.to_a
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
it 'queries again' do
|
1018
|
+
new_collection.find.to_a
|
1019
|
+
expect(Mongo::QueryCache.send(:cache_table).length).to eq(2)
|
1020
|
+
expect(events.length).to eq(2)
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
context 'with system collection' do
|
1025
|
+
let(:client) do
|
1026
|
+
ClientRegistry.instance.global_client('root_authorized').tap do |client|
|
1027
|
+
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
before do
|
1032
|
+
begin
|
1033
|
+
client.database.users.remove('alanturing')
|
1034
|
+
rescue Mongo::Error::OperationFailure
|
1035
|
+
# can be user not found, ignore
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
it 'does not use the query cache' do
|
1040
|
+
client['system.users'].find.to_a
|
1041
|
+
client['system.users'].find.to_a
|
1042
|
+
expect(events.length).to eq(2)
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
end
|