mongo 2.20.1 → 2.21.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
- data/README.md +3 -0
- data/Rakefile +2 -2
- data/lib/mongo/address.rb +22 -3
- data/lib/mongo/auth/aws/credentials_retriever.rb +70 -17
- data/lib/mongo/auth/base.rb +1 -1
- data/lib/mongo/bulk_write.rb +35 -2
- data/lib/mongo/client.rb +38 -6
- data/lib/mongo/client_encryption.rb +6 -3
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -1
- data/lib/mongo/cluster/sdam_flow.rb +20 -7
- data/lib/mongo/cluster.rb +14 -4
- data/lib/mongo/collection/helpers.rb +1 -1
- data/lib/mongo/collection/view/aggregation/behavior.rb +131 -0
- data/lib/mongo/collection/view/aggregation.rb +33 -99
- data/lib/mongo/collection/view/builder/aggregation.rb +1 -7
- data/lib/mongo/collection/view/change_stream.rb +80 -27
- data/lib/mongo/collection/view/iterable.rb +76 -60
- data/lib/mongo/collection/view/map_reduce.rb +25 -8
- data/lib/mongo/collection/view/readable.rb +79 -30
- data/lib/mongo/collection/view/writable.rb +109 -48
- data/lib/mongo/collection/view.rb +43 -3
- data/lib/mongo/collection.rb +158 -23
- data/lib/mongo/crypt/auto_encrypter.rb +4 -6
- data/lib/mongo/crypt/binding.rb +4 -4
- data/lib/mongo/crypt/context.rb +20 -14
- data/lib/mongo/crypt/encryption_io.rb +56 -26
- data/lib/mongo/crypt/explicit_encrypter.rb +49 -20
- data/lib/mongo/crypt/explicit_encryption_context.rb +17 -11
- data/lib/mongo/crypt/kms/azure/credentials_retriever.rb +22 -6
- data/lib/mongo/crypt/kms/gcp/credentials_retriever.rb +29 -4
- data/lib/mongo/csot_timeout_holder.rb +119 -0
- data/lib/mongo/cursor/kill_spec.rb +5 -2
- data/lib/mongo/cursor/nontailable.rb +27 -0
- data/lib/mongo/cursor.rb +86 -24
- data/lib/mongo/cursor_host.rb +82 -0
- data/lib/mongo/database/view.rb +81 -14
- data/lib/mongo/database.rb +88 -18
- data/lib/mongo/error/operation_failure.rb +209 -204
- data/lib/mongo/error/server_timeout_error.rb +12 -0
- data/lib/mongo/error/socket_timeout_error.rb +3 -1
- data/lib/mongo/error/timeout_error.rb +23 -0
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +45 -12
- data/lib/mongo/grid/stream/read.rb +15 -1
- data/lib/mongo/grid/stream/write.rb +21 -4
- data/lib/mongo/index/view.rb +77 -16
- data/lib/mongo/operation/context.rb +40 -2
- data/lib/mongo/operation/create_search_indexes/op_msg.rb +2 -2
- data/lib/mongo/operation/delete/op_msg.rb +2 -1
- data/lib/mongo/operation/drop_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation/find/op_msg.rb +45 -0
- data/lib/mongo/operation/get_more/op_msg.rb +33 -0
- data/lib/mongo/operation/insert/op_msg.rb +3 -2
- data/lib/mongo/operation/insert/result.rb +4 -2
- data/lib/mongo/operation/list_collections/result.rb +1 -1
- data/lib/mongo/operation/map_reduce/result.rb +1 -1
- data/lib/mongo/operation/op_msg_base.rb +3 -1
- data/lib/mongo/operation/result.rb +26 -5
- data/lib/mongo/operation/shared/executable.rb +12 -1
- data/lib/mongo/operation/shared/op_msg_executable.rb +4 -1
- data/lib/mongo/operation/shared/response_handling.rb +3 -3
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -1
- data/lib/mongo/operation/shared/timed.rb +52 -0
- data/lib/mongo/operation/shared/write.rb +4 -1
- data/lib/mongo/operation/update/op_msg.rb +2 -1
- data/lib/mongo/operation/update_search_index/op_msg.rb +2 -2
- data/lib/mongo/operation.rb +1 -0
- data/lib/mongo/protocol/message.rb +1 -4
- data/lib/mongo/protocol/msg.rb +2 -2
- data/lib/mongo/retryable/read_worker.rb +69 -29
- data/lib/mongo/retryable/write_worker.rb +49 -18
- data/lib/mongo/retryable.rb +8 -2
- data/lib/mongo/server/connection.rb +11 -5
- data/lib/mongo/server/connection_base.rb +22 -2
- data/lib/mongo/server/connection_pool.rb +32 -14
- data/lib/mongo/server/description/features.rb +1 -1
- data/lib/mongo/server/description.rb +18 -5
- data/lib/mongo/server/monitor.rb +7 -4
- data/lib/mongo/server/pending_connection.rb +7 -3
- data/lib/mongo/server/{round_trip_time_averager.rb → round_trip_time_calculator.rb} +25 -7
- data/lib/mongo/server.rb +11 -6
- data/lib/mongo/server_selector/base.rb +25 -9
- data/lib/mongo/session.rb +78 -9
- data/lib/mongo/socket/ssl.rb +109 -17
- data/lib/mongo/socket/tcp.rb +40 -6
- data/lib/mongo/socket.rb +154 -25
- data/lib/mongo/uri/options_mapper.rb +1 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +1 -0
- data/spec/atlas/atlas_connectivity_spec.rb +4 -0
- data/spec/atlas/operations_spec.rb +4 -0
- data/spec/integration/client_side_encryption/auto_encryption_mongocryptd_spawn_spec.rb +2 -1
- data/spec/integration/client_side_encryption/auto_encryption_spec.rb +494 -487
- data/spec/integration/client_side_encryption/on_demand_aws_credentials_spec.rb +1 -1
- data/spec/integration/client_side_encryption/range_explicit_encryption_prose_spec.rb +66 -22
- data/spec/integration/client_side_operations_timeout/encryption_prose_spec.rb +131 -0
- data/spec/integration/connection_pool_populator_spec.rb +2 -0
- data/spec/integration/cursor_pinning_spec.rb +15 -60
- data/spec/integration/cursor_reaping_spec.rb +1 -1
- data/spec/integration/docs_examples_spec.rb +1 -1
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +3 -3
- data/spec/integration/retryable_errors_spec.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +2 -1
- data/spec/integration/search_indexes_prose_spec.rb +4 -0
- data/spec/integration/server_spec.rb +4 -3
- data/spec/integration/transactions_api_examples_spec.rb +2 -0
- data/spec/kerberos/kerberos_spec.rb +4 -0
- data/spec/lite_spec_helper.rb +3 -1
- data/spec/mongo/auth/user/view_spec.rb +1 -1
- data/spec/mongo/caching_cursor_spec.rb +1 -1
- data/spec/mongo/client_encryption_spec.rb +1 -0
- data/spec/mongo/client_spec.rb +158 -4
- data/spec/mongo/collection/view/aggregation_spec.rb +14 -39
- data/spec/mongo/collection/view/change_stream_spec.rb +3 -3
- data/spec/mongo/collection_spec.rb +5 -6
- data/spec/mongo/crypt/auto_encrypter_spec.rb +14 -12
- data/spec/mongo/crypt/data_key_context_spec.rb +3 -1
- data/spec/mongo/crypt/explicit_encryption_context_spec.rb +2 -2
- data/spec/mongo/crypt/handle_spec.rb +1 -1
- data/spec/mongo/cursor_spec.rb +26 -9
- data/spec/mongo/error/operation_failure_heavy_spec.rb +2 -2
- data/spec/mongo/operation/context_spec.rb +79 -0
- data/spec/mongo/operation/create/op_msg_spec.rb +106 -110
- data/spec/mongo/operation/delete/op_msg_spec.rb +6 -5
- data/spec/mongo/operation/find/op_msg_spec.rb +66 -0
- data/spec/mongo/operation/get_more/op_msg_spec.rb +65 -0
- data/spec/mongo/operation/insert/op_msg_spec.rb +128 -131
- data/spec/mongo/operation/shared/csot/examples.rb +113 -0
- data/spec/mongo/query_cache_spec.rb +243 -225
- data/spec/mongo/retryable_spec.rb +1 -0
- data/spec/mongo/server/round_trip_time_calculator_spec.rb +120 -0
- data/spec/mongo/socket/ssl_spec.rb +0 -10
- data/spec/runners/change_streams/test.rb +2 -2
- data/spec/runners/crud/operation.rb +1 -1
- data/spec/runners/crud/verifier.rb +3 -1
- data/spec/runners/transactions/operation.rb +4 -6
- data/spec/runners/unified/ambiguous_operations.rb +13 -0
- data/spec/runners/unified/assertions.rb +4 -0
- data/spec/runners/unified/change_stream_operations.rb +14 -24
- data/spec/runners/unified/crud_operations.rb +82 -59
- data/spec/runners/unified/ddl_operations.rb +38 -7
- data/spec/runners/unified/grid_fs_operations.rb +37 -2
- data/spec/runners/unified/support_operations.rb +43 -4
- data/spec/runners/unified/test.rb +22 -10
- data/spec/runners/unified.rb +1 -1
- data/spec/solo/clean_exit_spec.rb +2 -0
- data/spec/spec_tests/client_side_operations_timeout_spec.rb +15 -0
- data/spec/spec_tests/data/change_streams_unified/change-streams-clusterTime.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-disambiguatedPaths.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-errors.yml +3 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-pre_and_post_images.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-allowlist.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-resume-errorLabels.yml +1 -1
- data/spec/spec_tests/data/change_streams_unified/change-streams-showExpandedEvents.yml +1 -1
- data/spec/spec_tests/data/client_side_encryption/badQueries.yml +2 -1
- data/spec/spec_tests/data/client_side_encryption/timeoutMS.yml +67 -0
- data/spec/spec_tests/data/client_side_operations_timeout/bulkWrite.yml +87 -0
- data/spec/spec_tests/data/client_side_operations_timeout/change-streams.yml +358 -0
- data/spec/spec_tests/data/client_side_operations_timeout/close-cursors.yml +129 -0
- data/spec/spec_tests/data/client_side_operations_timeout/command-execution.yml +250 -0
- data/spec/spec_tests/data/client_side_operations_timeout/convenient-transactions.yml +113 -0
- data/spec/spec_tests/data/client_side_operations_timeout/cursors.yml +70 -0
- data/spec/spec_tests/data/client_side_operations_timeout/deprecated-options.yml +3982 -0
- data/spec/spec_tests/data/client_side_operations_timeout/error-transformations.yml +96 -0
- data/spec/spec_tests/data/client_side_operations_timeout/global-timeoutMS.yml +3236 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-advanced.yml +207 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-delete.yml +152 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-download.yml +182 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-find.yml +100 -0
- data/spec/spec_tests/data/client_side_operations_timeout/gridfs-upload.yml +249 -0
- data/spec/spec_tests/data/client_side_operations_timeout/legacy-timeouts.yml +204 -0
- data/spec/spec_tests/data/client_side_operations_timeout/non-tailable-cursors.yml +307 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-collection-timeoutMS.yml +1877 -0
- data/spec/spec_tests/data/client_side_operations_timeout/override-operation-timeoutMS.yml +1918 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-legacy-timeouts.yml +1676 -0
- data/spec/spec_tests/data/client_side_operations_timeout/retryability-timeoutMS.yml +2824 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-inherit-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-operation-timeoutMS.yml +171 -0
- data/spec/spec_tests/data/client_side_operations_timeout/sessions-override-timeoutMS.yml +168 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-awaitData.yml +247 -0
- data/spec/spec_tests/data/client_side_operations_timeout/tailable-non-awaitData.yml +181 -0
- data/spec/spec_tests/data/crud_unified/aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/db-aggregate-write-readPreference.yml +4 -0
- data/spec/spec_tests/data/crud_unified/find-test-all-options.yml +29 -0
- data/spec/spec_tests/server_selection_rtt_spec.rb +6 -6
- data/spec/support/certificates/atlas-ocsp-ca.crt +81 -83
- data/spec/support/certificates/atlas-ocsp.crt +107 -107
- data/spec/support/cluster_tools.rb +3 -3
- data/spec/support/common_shortcuts.rb +2 -2
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Date.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DecimalPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoubleNoPrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-DoublePrecision.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Int.json +1 -1
- data/spec/support/crypt/encrypted_fields/range-encryptedFields-Long.json +1 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/utils.rb +3 -1
- metadata +78 -91
- data/spec/mongo/server/round_trip_time_averager_spec.rb +0 -48
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Date-Update.yml +0 -253
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Aggregate.yml +0 -1688
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Correctness.yml +0 -294
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Delete.yml +0 -906
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-FindOneAndUpdate.yml +0 -1685
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-InsertFind.yml +0 -1681
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Decimal-Update.yml +0 -1698
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Aggregate.yml +0 -330
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Delete.yml +0 -227
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.yml +0 -328
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DecimalPrecision-Update.yml +0 -337
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Aggregate.yml +0 -914
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Correctness.yml +0 -293
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Delete.yml +0 -519
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-FindOneAndUpdate.yml +0 -912
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-InsertFind.yml +0 -908
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Double-Update.yml +0 -925
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Aggregate.yml +0 -326
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Correctness.yml +0 -425
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Delete.yml +0 -225
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-FindOneAndUpdate.yml +0 -324
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-InsertFind.yml +0 -320
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-DoublePrecision-Update.yml +0 -339
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Correctness.yml +0 -424
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Int-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Aggregate.yml +0 -242
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Correctness.yml +0 -423
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Delete.yml +0 -183
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-FindOneAndUpdate.yml +0 -240
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-InsertFind.yml +0 -236
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-Long-Update.yml +0 -255
- data/spec/spec_tests/data/client_side_encryption/fle2v2-Range-WrongType.yml +0 -44
data/spec/mongo/client_spec.rb
CHANGED
@@ -561,6 +561,75 @@ describe Mongo::Client do
|
|
561
561
|
expect(command['comment']).to eq('comment')
|
562
562
|
end
|
563
563
|
end
|
564
|
+
|
565
|
+
context 'with timeout_ms' do
|
566
|
+
# To make it easier with failCommand
|
567
|
+
require_topology :single
|
568
|
+
min_server_version '4.4'
|
569
|
+
|
570
|
+
before do
|
571
|
+
root_authorized_client.use('admin').command({
|
572
|
+
configureFailPoint: "failCommand",
|
573
|
+
mode: "alwaysOn",
|
574
|
+
data: {
|
575
|
+
failCommands: ["listDatabases"],
|
576
|
+
blockConnection: true,
|
577
|
+
blockTimeMS: 100
|
578
|
+
}
|
579
|
+
})
|
580
|
+
end
|
581
|
+
|
582
|
+
after do
|
583
|
+
root_authorized_client.use('admin').command({
|
584
|
+
configureFailPoint: "failCommand",
|
585
|
+
mode: "off"
|
586
|
+
})
|
587
|
+
end
|
588
|
+
|
589
|
+
context 'when timeout_ms is set on command level' do
|
590
|
+
context 'when there is not enough time' do
|
591
|
+
it 'raises' do
|
592
|
+
expect do
|
593
|
+
monitored_client.database_names({}, timeout_ms: 50)
|
594
|
+
end.to raise_error(Mongo::Error::TimeoutError)
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
context 'when there is enough time' do
|
599
|
+
it 'does not raise' do
|
600
|
+
expect do
|
601
|
+
monitored_client.database_names({}, timeout_ms: 200)
|
602
|
+
end.not_to raise_error
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
context 'when timeout_ms is set on client level' do
|
608
|
+
context 'when there is not enough time' do
|
609
|
+
let(:client) do
|
610
|
+
root_authorized_client.with(timeout_ms: 50)
|
611
|
+
end
|
612
|
+
|
613
|
+
it 'raises' do
|
614
|
+
expect do
|
615
|
+
client.database_names({})
|
616
|
+
end.to raise_error(Mongo::Error::TimeoutError)
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
context 'when there is enough time' do
|
621
|
+
let(:client) do
|
622
|
+
root_authorized_client.with(timeout_ms: 200)
|
623
|
+
end
|
624
|
+
|
625
|
+
it 'does not raise' do
|
626
|
+
expect do
|
627
|
+
monitored_client.database_names({})
|
628
|
+
end.not_to raise_error
|
629
|
+
end
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
564
633
|
end
|
565
634
|
|
566
635
|
describe '#list_databases' do
|
@@ -572,8 +641,6 @@ describe Mongo::Client do
|
|
572
641
|
end
|
573
642
|
|
574
643
|
context 'when filter criteria is present' do
|
575
|
-
min_server_fcv '3.6'
|
576
|
-
|
577
644
|
include_context 'ensure test db exists'
|
578
645
|
|
579
646
|
let(:result) do
|
@@ -591,8 +658,6 @@ describe Mongo::Client do
|
|
591
658
|
end
|
592
659
|
|
593
660
|
context 'when name_only is true' do
|
594
|
-
min_server_fcv '3.6'
|
595
|
-
|
596
661
|
let(:command) do
|
597
662
|
Utils.get_command_event(root_authorized_client, 'listDatabases') do |client|
|
598
663
|
client.list_databases({}, true)
|
@@ -667,6 +732,75 @@ describe Mongo::Client do
|
|
667
732
|
expect(command['comment']).to eq('comment')
|
668
733
|
end
|
669
734
|
end
|
735
|
+
|
736
|
+
context 'with timeout_ms' do
|
737
|
+
# To make it easier with failCommand
|
738
|
+
require_topology :single
|
739
|
+
min_server_version '4.4'
|
740
|
+
|
741
|
+
before do
|
742
|
+
root_authorized_client.use('admin').command({
|
743
|
+
configureFailPoint: "failCommand",
|
744
|
+
mode: "alwaysOn",
|
745
|
+
data: {
|
746
|
+
failCommands: ["listDatabases"],
|
747
|
+
blockConnection: true,
|
748
|
+
blockTimeMS: 100
|
749
|
+
}
|
750
|
+
})
|
751
|
+
end
|
752
|
+
|
753
|
+
after do
|
754
|
+
root_authorized_client.use('admin').command({
|
755
|
+
configureFailPoint: "failCommand",
|
756
|
+
mode: "off"
|
757
|
+
})
|
758
|
+
end
|
759
|
+
|
760
|
+
context 'when timeout_ms is set on command level' do
|
761
|
+
context 'when there is not enough time' do
|
762
|
+
it 'raises' do
|
763
|
+
expect do
|
764
|
+
monitored_client.list_databases({}, false, timeout_ms: 50)
|
765
|
+
end.to raise_error(Mongo::Error::TimeoutError)
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
769
|
+
context 'when there is enough time' do
|
770
|
+
it 'does not raise' do
|
771
|
+
expect do
|
772
|
+
monitored_client.list_databases({}, false, timeout_ms: 200)
|
773
|
+
end.not_to raise_error
|
774
|
+
end
|
775
|
+
end
|
776
|
+
end
|
777
|
+
|
778
|
+
context 'when timeout_ms is set on client level' do
|
779
|
+
context 'when there is not enough time' do
|
780
|
+
let(:client) do
|
781
|
+
root_authorized_client.with(timeout_ms: 50)
|
782
|
+
end
|
783
|
+
|
784
|
+
it 'raises' do
|
785
|
+
expect do
|
786
|
+
client.list_databases({})
|
787
|
+
end.to raise_error(Mongo::Error::TimeoutError)
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
context 'when there is enough time' do
|
792
|
+
let(:client) do
|
793
|
+
root_authorized_client.with(timeout_ms: 200)
|
794
|
+
end
|
795
|
+
|
796
|
+
it 'does not raise' do
|
797
|
+
expect do
|
798
|
+
monitored_client.list_databases({})
|
799
|
+
end.not_to raise_error
|
800
|
+
end
|
801
|
+
end
|
802
|
+
end
|
803
|
+
end
|
670
804
|
end
|
671
805
|
|
672
806
|
describe '#list_mongo_databases' do
|
@@ -1156,6 +1290,26 @@ describe Mongo::Client do
|
|
1156
1290
|
}.to raise_exception(Mongo::Error::InvalidSession)
|
1157
1291
|
end
|
1158
1292
|
end
|
1293
|
+
|
1294
|
+
context 'when CSOT is set on the client' do
|
1295
|
+
require_topology :replica_set
|
1296
|
+
|
1297
|
+
let(:timeout_ms) { 10 }
|
1298
|
+
|
1299
|
+
let(:timeout_sec) { timeout_ms / 1_000.0 }
|
1300
|
+
|
1301
|
+
let(:client) do
|
1302
|
+
authorized_client.with(timeout_ms: timeout_ms)
|
1303
|
+
end
|
1304
|
+
|
1305
|
+
it 'uses CSOT timeout set on the client' do
|
1306
|
+
expect_any_instance_of(Mongo::ServerSelector::PrimaryPreferred).to(
|
1307
|
+
receive(:select_server).with(anything, {timeout: timeout_sec}).and_call_original
|
1308
|
+
)
|
1309
|
+
|
1310
|
+
client.start_session
|
1311
|
+
end
|
1312
|
+
end
|
1159
1313
|
end
|
1160
1314
|
|
1161
1315
|
describe '#summary' do
|
@@ -156,8 +156,6 @@ describe Mongo::Collection::View::Aggregation do
|
|
156
156
|
end
|
157
157
|
|
158
158
|
context 'when the initial response has no results but an active cursor' do
|
159
|
-
min_server_fcv '3.2'
|
160
|
-
|
161
159
|
let(:documents) do
|
162
160
|
[
|
163
161
|
{ city: 'a'*6000000 },
|
@@ -166,7 +164,7 @@ describe Mongo::Collection::View::Aggregation do
|
|
166
164
|
end
|
167
165
|
|
168
166
|
let(:options) do
|
169
|
-
{
|
167
|
+
{}
|
170
168
|
end
|
171
169
|
|
172
170
|
let(:pipeline) do
|
@@ -486,48 +484,25 @@ describe Mongo::Collection::View::Aggregation do
|
|
486
484
|
end
|
487
485
|
end
|
488
486
|
|
489
|
-
context 'when
|
490
|
-
|
491
|
-
context 'when use_cursor is true' do
|
492
|
-
|
493
|
-
context 'when batch_size is set' do
|
494
|
-
|
495
|
-
let(:options) do
|
496
|
-
{ :use_cursor => true,
|
497
|
-
:batch_size => 10
|
498
|
-
}
|
499
|
-
end
|
500
|
-
|
501
|
-
it 'sets a batch size document in the spec' do
|
502
|
-
expect(aggregation_spec[:selector][:cursor][:batchSize]).to eq(options[:batch_size])
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
context 'when batch_size is not set' do
|
507
|
-
|
508
|
-
let(:options) do
|
509
|
-
{ :use_cursor => true }
|
510
|
-
end
|
487
|
+
context 'when batch_size is set' do
|
511
488
|
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
end
|
489
|
+
let(:options) do
|
490
|
+
{ :batch_size => 10 }
|
491
|
+
end
|
516
492
|
|
493
|
+
it 'sets a batch size document in the spec' do
|
494
|
+
expect(aggregation_spec[:selector][:cursor][:batchSize]).to eq(options[:batch_size])
|
517
495
|
end
|
496
|
+
end
|
518
497
|
|
519
|
-
|
498
|
+
context 'when batch_size is not set' do
|
520
499
|
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
context 'when batch_size is set' do
|
500
|
+
let(:options) do
|
501
|
+
{}
|
502
|
+
end
|
526
503
|
|
527
|
-
|
528
|
-
|
529
|
-
end
|
530
|
-
end
|
504
|
+
it 'sets an empty document in the spec' do
|
505
|
+
expect(aggregation_spec[:selector][:cursor]).to eq({})
|
531
506
|
end
|
532
507
|
end
|
533
508
|
end
|
@@ -507,7 +507,7 @@ describe Mongo::Collection::View::ChangeStream do
|
|
507
507
|
end
|
508
508
|
|
509
509
|
it 'includes the max_await_time value in the formatted string' do
|
510
|
-
expect(change_stream.inspect).to include({ max_await_time_ms
|
510
|
+
expect(change_stream.inspect).to include({ 'max_await_time_ms' => 10 }.to_s)
|
511
511
|
end
|
512
512
|
end
|
513
513
|
|
@@ -518,7 +518,7 @@ describe Mongo::Collection::View::ChangeStream do
|
|
518
518
|
end
|
519
519
|
|
520
520
|
it 'includes the batch_size value in the formatted string' do
|
521
|
-
expect(change_stream.inspect).to include({ batch_size
|
521
|
+
expect(change_stream.inspect).to include({ 'batch_size' => 5 }.to_s)
|
522
522
|
end
|
523
523
|
end
|
524
524
|
|
@@ -529,7 +529,7 @@ describe Mongo::Collection::View::ChangeStream do
|
|
529
529
|
end
|
530
530
|
|
531
531
|
it 'includes the collation value in the formatted string' do
|
532
|
-
expect(change_stream.inspect).to include({ 'collation' => { locale
|
532
|
+
expect(change_stream.inspect).to include({ 'collation' => { 'locale' => 'en_US', 'strength' => 2 } }.to_s)
|
533
533
|
end
|
534
534
|
end
|
535
535
|
|
@@ -828,13 +828,12 @@ describe Mongo::Collection do
|
|
828
828
|
|
829
829
|
let(:enum) { change_stream.to_enum }
|
830
830
|
|
831
|
+
let(:get_more) { subscriber.started_events.detect { |e| e.command['getMore'] }.command }
|
832
|
+
|
831
833
|
it 'sets the option correctly' do
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
end
|
836
|
-
end
|
837
|
-
enum.next
|
834
|
+
enum.try_next
|
835
|
+
expect(get_more).not_to be_nil
|
836
|
+
expect(get_more['maxTimeMS']).to be == 3000
|
838
837
|
end
|
839
838
|
|
840
839
|
it "waits the appropriate amount of time" do
|
@@ -58,6 +58,8 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
58
58
|
)
|
59
59
|
end
|
60
60
|
|
61
|
+
let(:operation_context) { Mongo::Operation::Context.new }
|
62
|
+
|
61
63
|
shared_context 'with jsonSchema validator' do
|
62
64
|
before do
|
63
65
|
users_collection = client.use(db_name)[collection_name]
|
@@ -81,14 +83,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
81
83
|
shared_examples 'a functioning auto encrypter' do
|
82
84
|
describe '#encrypt' do
|
83
85
|
it 'replaces the ssn field with a BSON::Binary' do
|
84
|
-
result = auto_encrypter.encrypt(db_name, command)
|
86
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
85
87
|
expect(result).to eq(encrypted_command)
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
91
|
describe '#decrypt' do
|
90
92
|
it 'returns the unencrypted document' do
|
91
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
93
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
92
94
|
expect(result).to eq(command)
|
93
95
|
end
|
94
96
|
end
|
@@ -329,14 +331,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
329
331
|
|
330
332
|
describe '#encrypt' do
|
331
333
|
it 'does not perform encryption' do
|
332
|
-
result = auto_encrypter.encrypt(db_name, command)
|
334
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
333
335
|
expect(result).to eq(command)
|
334
336
|
end
|
335
337
|
end
|
336
338
|
|
337
339
|
describe '#decrypt' do
|
338
340
|
it 'still performs decryption' do
|
339
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
341
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
340
342
|
expect(result).to eq(command)
|
341
343
|
end
|
342
344
|
end
|
@@ -347,14 +349,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
347
349
|
|
348
350
|
describe '#encrypt' do
|
349
351
|
it 'does not perform encryption' do
|
350
|
-
result = auto_encrypter.encrypt(db_name, command)
|
352
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
351
353
|
expect(result).to eq(command)
|
352
354
|
end
|
353
355
|
end
|
354
356
|
|
355
357
|
describe '#decrypt' do
|
356
358
|
it 'still performs decryption' do
|
357
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
359
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
358
360
|
expect(result).to eq(command)
|
359
361
|
end
|
360
362
|
end
|
@@ -365,14 +367,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
365
367
|
|
366
368
|
describe '#encrypt' do
|
367
369
|
it 'does not perform encryption' do
|
368
|
-
result = auto_encrypter.encrypt(db_name, command)
|
370
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
369
371
|
expect(result).to eq(command)
|
370
372
|
end
|
371
373
|
end
|
372
374
|
|
373
375
|
describe '#decrypt' do
|
374
376
|
it 'still performs decryption' do
|
375
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
377
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
376
378
|
expect(result).to eq(command)
|
377
379
|
end
|
378
380
|
end
|
@@ -383,14 +385,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
383
385
|
|
384
386
|
describe '#encrypt' do
|
385
387
|
it 'does not perform encryption' do
|
386
|
-
result = auto_encrypter.encrypt(db_name, command)
|
388
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
387
389
|
expect(result).to eq(command)
|
388
390
|
end
|
389
391
|
end
|
390
392
|
|
391
393
|
describe '#decrypt' do
|
392
394
|
it 'still performs decryption' do
|
393
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
395
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
394
396
|
expect(result).to eq(command)
|
395
397
|
end
|
396
398
|
end
|
@@ -401,14 +403,14 @@ describe Mongo::Crypt::AutoEncrypter do
|
|
401
403
|
|
402
404
|
describe '#encrypt' do
|
403
405
|
it 'does not perform encryption' do
|
404
|
-
result = auto_encrypter.encrypt(db_name, command)
|
406
|
+
result = auto_encrypter.encrypt(db_name, command, operation_context)
|
405
407
|
expect(result).to eq(command)
|
406
408
|
end
|
407
409
|
end
|
408
410
|
|
409
411
|
describe '#decrypt' do
|
410
412
|
it 'still performs decryption' do
|
411
|
-
result = auto_encrypter.decrypt(encrypted_command)
|
413
|
+
result = auto_encrypter.decrypt(encrypted_command, operation_context)
|
412
414
|
expect(result).to eq(command)
|
413
415
|
end
|
414
416
|
end
|
@@ -136,8 +136,10 @@ describe Mongo::Crypt::DataKeyContext do
|
|
136
136
|
)
|
137
137
|
end
|
138
138
|
|
139
|
+
let(:operation_context) { Mongo::Operation::Context.new }
|
140
|
+
|
139
141
|
it 'creates a data key' do
|
140
|
-
expect(context.run_state_machine).to be_a_kind_of(Hash)
|
142
|
+
expect(context.run_state_machine(operation_context)).to be_a_kind_of(Hash)
|
141
143
|
end
|
142
144
|
end
|
143
145
|
end
|
@@ -139,7 +139,7 @@ describe Mongo::Crypt::ExplicitEncryptionContext do
|
|
139
139
|
value,
|
140
140
|
options.merge(query_type: "equality")
|
141
141
|
)
|
142
|
-
end.to raise_error(ArgumentError, /query_type is allowed only for "Indexed" or "
|
142
|
+
end.to raise_error(ArgumentError, /query_type is allowed only for "Indexed" or "Range" algorithm/)
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
@@ -154,7 +154,7 @@ describe Mongo::Crypt::ExplicitEncryptionContext do
|
|
154
154
|
value,
|
155
155
|
options.merge(contention_factor: 10)
|
156
156
|
)
|
157
|
-
end.to raise_error(ArgumentError, /contention_factor is allowed only for "Indexed" or "
|
157
|
+
end.to raise_error(ArgumentError, /contention_factor is allowed only for "Indexed" or "Range" algorithm/)
|
158
158
|
end
|
159
159
|
end
|
160
160
|
|
@@ -188,7 +188,7 @@ describe Mongo::Crypt::Handle do
|
|
188
188
|
end
|
189
189
|
|
190
190
|
it 'raises an exception' do
|
191
|
-
expect { handle }.to raise_error(Mongo::Error::CryptError,
|
191
|
+
expect { handle }.to raise_error(Mongo::Error::CryptError, /local key must be 96 bytes \(libmongocrypt error code 1\)/)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
data/spec/mongo/cursor_spec.rb
CHANGED
@@ -8,6 +8,10 @@ describe Mongo::Cursor do
|
|
8
8
|
authorized_client['cursor_spec_collection']
|
9
9
|
end
|
10
10
|
|
11
|
+
let(:context) do
|
12
|
+
Mongo::Operation::Context.new(client: authorized_client)
|
13
|
+
end
|
14
|
+
|
11
15
|
before do
|
12
16
|
authorized_collection.drop
|
13
17
|
end
|
@@ -18,7 +22,7 @@ describe Mongo::Cursor do
|
|
18
22
|
end
|
19
23
|
|
20
24
|
let(:reply) do
|
21
|
-
view.send(:send_initial_query, server)
|
25
|
+
view.send(:send_initial_query, server, context)
|
22
26
|
end
|
23
27
|
|
24
28
|
let(:cursor) do
|
@@ -118,7 +122,7 @@ describe Mongo::Cursor do
|
|
118
122
|
end
|
119
123
|
|
120
124
|
let(:reply) do
|
121
|
-
view.send(:send_initial_query, server)
|
125
|
+
view.send(:send_initial_query, server, context)
|
122
126
|
end
|
123
127
|
|
124
128
|
let(:cursor) do
|
@@ -170,7 +174,11 @@ describe Mongo::Cursor do
|
|
170
174
|
|
171
175
|
before do
|
172
176
|
expect(cursor).to receive(:get_more_operation).and_return(op).ordered
|
173
|
-
|
177
|
+
if SpecConfig.instance.connect_options[:connect] == :load_balanced
|
178
|
+
expect(op).to receive(:execute_with_connection).and_raise(Mongo::Error::SocketError).ordered
|
179
|
+
else
|
180
|
+
expect(op).to receive(:execute).and_raise(Mongo::Error::SocketError).ordered
|
181
|
+
end
|
174
182
|
end
|
175
183
|
|
176
184
|
it 'raises the error' do
|
@@ -617,6 +625,9 @@ describe Mongo::Cursor do
|
|
617
625
|
allow(reply).to receive(:connection_description).and_return(conn_desc)
|
618
626
|
allow(reply).to receive(:cursor_id).and_return(42)
|
619
627
|
allow(reply).to receive(:connection_global_id).and_return(1)
|
628
|
+
if SpecConfig.instance.connect_options[:connect] == :load_balanced
|
629
|
+
allow(reply).to receive(:connection).and_return(nil)
|
630
|
+
end
|
620
631
|
end
|
621
632
|
end
|
622
633
|
|
@@ -645,7 +656,7 @@ describe Mongo::Cursor do
|
|
645
656
|
end
|
646
657
|
|
647
658
|
let(:reply) do
|
648
|
-
view.send(:send_initial_query, authorized_primary)
|
659
|
+
view.send(:send_initial_query, authorized_primary, context)
|
649
660
|
end
|
650
661
|
|
651
662
|
let(:cursor) do
|
@@ -721,7 +732,7 @@ describe Mongo::Cursor do
|
|
721
732
|
end
|
722
733
|
|
723
734
|
let(:reply) do
|
724
|
-
view.send(:send_initial_query, server)
|
735
|
+
view.send(:send_initial_query, server, context)
|
725
736
|
end
|
726
737
|
|
727
738
|
let(:cursor) do
|
@@ -770,10 +781,16 @@ describe Mongo::Cursor do
|
|
770
781
|
|
771
782
|
it 'does not raise an error' do
|
772
783
|
cursor
|
773
|
-
|
774
|
-
expect(
|
775
|
-
|
776
|
-
|
784
|
+
if SpecConfig.instance.connect_options[:connect] == :load_balanced
|
785
|
+
expect(cursor.connection).to receive(:deliver)
|
786
|
+
.at_least(:once)
|
787
|
+
.and_raise(Mongo::Error::SocketError, "test error")
|
788
|
+
else
|
789
|
+
server.with_connection do |conn|
|
790
|
+
expect(conn).to receive(:deliver)
|
791
|
+
.at_least(:once)
|
792
|
+
.and_raise(Mongo::Error::SocketError, "test error")
|
793
|
+
end
|
777
794
|
end
|
778
795
|
expect do
|
779
796
|
cursor.close
|
@@ -39,7 +39,7 @@ describe Mongo::Error::OperationFailure do
|
|
39
39
|
|
40
40
|
begin
|
41
41
|
authorized_client['foo'].insert_one(test: 1)
|
42
|
-
rescue Mongo::Error::OperationFailure => exc
|
42
|
+
rescue Mongo::Error::OperationFailure::Family => exc
|
43
43
|
expect(exc.details).to eq(exc.document['writeConcernError']['errInfo'])
|
44
44
|
expect(exc.server_message).to eq(exc.document['writeConcernError']['errmsg'])
|
45
45
|
expect(exc.code).to eq(exc.document['writeConcernError']['code'])
|
@@ -90,7 +90,7 @@ describe Mongo::Error::OperationFailure do
|
|
90
90
|
it 'succeeds and prints the error' do
|
91
91
|
begin
|
92
92
|
collection.insert_one({x: 1})
|
93
|
-
rescue Mongo::Error::OperationFailure => e
|
93
|
+
rescue Mongo::Error::OperationFailure::Family => e
|
94
94
|
insert_events = subscriber.succeeded_events.select { |e| e.command_name == "insert" }
|
95
95
|
expect(insert_events.length).to eq 1
|
96
96
|
expect(e.message).to match(/\[#{e.code}(:.*)?\].+ -- .+/)
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lite_spec_helper'
|
4
|
+
|
5
|
+
describe Mongo::Operation::Context do
|
6
|
+
describe '#initialize' do
|
7
|
+
context 'when timeout_ms is negative' do
|
8
|
+
it 'raises an error' do
|
9
|
+
expect do
|
10
|
+
described_class.new(operation_timeouts: { operation_timeout_ms: -1 })
|
11
|
+
end.to raise_error ArgumentError, /must be a non-negative integer/
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#deadline' do
|
17
|
+
let(:context) { described_class.new(operation_timeouts: { operation_timeout_ms: timeout_ms }) }
|
18
|
+
|
19
|
+
context 'when timeout_ms is nil' do
|
20
|
+
let(:timeout_ms) { nil }
|
21
|
+
|
22
|
+
it 'returns nil' do
|
23
|
+
expect(context.deadline).to be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when timeout_ms is zero' do
|
28
|
+
let(:timeout_ms) { 0 }
|
29
|
+
|
30
|
+
it 'returns nil' do
|
31
|
+
expect(context.deadline).to eq(0)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when timeout_ms is positive' do
|
36
|
+
before do
|
37
|
+
allow(Mongo::Utils).to receive(:monotonic_time).and_return(100.0)
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:timeout_ms) { 10_000 }
|
41
|
+
|
42
|
+
it 'calculates the deadline' do
|
43
|
+
expect(context.deadline).to eq(110)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#remaining_timeout_ms' do
|
49
|
+
let(:context) { described_class.new(operation_timeouts: { operation_timeout_ms: timeout_ms }) }
|
50
|
+
|
51
|
+
context 'when timeout_ms is nil' do
|
52
|
+
let(:timeout_ms) { nil }
|
53
|
+
|
54
|
+
it 'returns nil' do
|
55
|
+
expect(context.remaining_timeout_ms).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when timeout_ms is zero' do
|
60
|
+
let(:timeout_ms) { 0 }
|
61
|
+
|
62
|
+
it 'returns nil' do
|
63
|
+
expect(context.remaining_timeout_ms).to be_nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'when timeout_ms is positive' do
|
68
|
+
before do
|
69
|
+
allow(Mongo::Utils).to receive(:monotonic_time).and_return(100.0, 105.0)
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:timeout_ms) { 10_000 }
|
73
|
+
|
74
|
+
it 'calculates the remaining time' do
|
75
|
+
expect(context.remaining_timeout_ms).to eq(5_000)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|