mongo 2.9.2 → 2.10.0.rc0
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 +0 -0
- data/lib/mongo.rb +1 -0
- data/lib/mongo/auth/user/view.rb +4 -4
- data/lib/mongo/bulk_write.rb +14 -8
- data/lib/mongo/bulk_write/result.rb +1 -1
- data/lib/mongo/bulk_write/result_combiner.rb +2 -2
- data/lib/mongo/bulk_write/transformable.rb +17 -9
- data/lib/mongo/client.rb +107 -16
- data/lib/mongo/cluster.rb +47 -25
- data/lib/mongo/cluster/topology/replica_set_no_primary.rb +1 -1
- data/lib/mongo/cluster_time.rb +139 -0
- data/lib/mongo/collection.rb +84 -25
- data/lib/mongo/collection/view.rb +7 -3
- data/lib/mongo/collection/view/aggregation.rb +4 -4
- data/lib/mongo/collection/view/builder/aggregation.rb +31 -6
- data/lib/mongo/collection/view/builder/find_command.rb +4 -1
- data/lib/mongo/collection/view/builder/map_reduce.rb +4 -1
- data/lib/mongo/collection/view/change_stream.rb +54 -66
- data/lib/mongo/collection/view/iterable.rb +2 -2
- data/lib/mongo/collection/view/map_reduce.rb +6 -4
- data/lib/mongo/collection/view/readable.rb +36 -16
- data/lib/mongo/collection/view/writable.rb +68 -22
- data/lib/mongo/cursor.rb +87 -20
- data/lib/mongo/database.rb +47 -43
- data/lib/mongo/database/view.rb +54 -11
- data/lib/mongo/error.rb +13 -4
- data/lib/mongo/error/invalid_write_concern.rb +2 -2
- data/lib/mongo/error/operation_failure.rb +65 -11
- data/lib/mongo/error/parser.rb +41 -8
- data/lib/mongo/grid/fs_bucket.rb +26 -6
- data/lib/mongo/grid/stream/read.rb +9 -2
- data/lib/mongo/grid/stream/write.rb +21 -5
- data/lib/mongo/index/view.rb +3 -3
- data/lib/mongo/lint.rb +10 -3
- data/lib/mongo/operation.rb +2 -0
- data/lib/mongo/operation/aggregate/result.rb +19 -6
- data/lib/mongo/operation/collections_info.rb +1 -1
- data/lib/mongo/operation/get_more/result.rb +9 -0
- data/lib/mongo/operation/list_collections/command.rb +1 -3
- data/lib/mongo/operation/list_collections/op_msg.rb +1 -2
- data/lib/mongo/operation/parallel_scan/command.rb +4 -1
- data/lib/mongo/operation/parallel_scan/op_msg.rb +4 -1
- data/lib/mongo/operation/result.rb +27 -4
- data/lib/mongo/operation/shared/executable.rb +19 -5
- data/lib/mongo/operation/shared/executable_no_validate.rb +1 -2
- data/lib/mongo/operation/shared/executable_transaction_label.rb +0 -9
- data/lib/mongo/operation/shared/polymorphic_result.rb +9 -1
- data/lib/mongo/operation/shared/result/aggregatable.rb +2 -2
- data/lib/mongo/operation/shared/sessions_supported.rb +42 -32
- data/lib/mongo/operation/shared/specifiable.rb +40 -0
- data/lib/mongo/operation/shared/unpinnable.rb +39 -0
- data/lib/mongo/operation/shared/write.rb +1 -1
- data/lib/mongo/protocol/update.rb +6 -2
- data/lib/mongo/retryable.rb +79 -39
- data/lib/mongo/server/connection.rb +10 -3
- data/lib/mongo/server/description.rb +25 -1
- data/lib/mongo/server/monitor/connection.rb +1 -1
- data/lib/mongo/server_selector.rb +10 -0
- data/lib/mongo/server_selector/selectable.rb +172 -32
- data/lib/mongo/session.rb +654 -581
- data/lib/mongo/session/session_pool.rb +1 -1
- data/lib/mongo/socket.rb +7 -28
- data/lib/mongo/socket/ssl.rb +26 -1
- data/lib/mongo/socket/tcp.rb +3 -0
- data/lib/mongo/socket/unix.rb +3 -0
- data/lib/mongo/uri.rb +112 -265
- data/lib/mongo/uri/srv_protocol.rb +4 -1
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo/write_concern.rb +10 -29
- data/lib/mongo/write_concern/acknowledged.rb +12 -0
- data/lib/mongo/write_concern/base.rb +17 -13
- data/lib/mongo/write_concern/unacknowledged.rb +12 -0
- data/spec/atlas/atlas_connectivity_spec.rb +7 -37
- data/spec/atlas/operations_spec.rb +25 -0
- data/spec/integration/change_stream_examples_spec.rb +45 -31
- data/spec/integration/change_stream_spec.rb +305 -5
- data/spec/integration/client_spec.rb +44 -0
- data/spec/integration/command_monitoring_spec.rb +1 -0
- data/spec/integration/command_spec.rb +7 -1
- data/spec/integration/mmapv1_spec.rb +28 -0
- data/spec/integration/mongos_pinning_spec.rb +34 -0
- data/spec/integration/operation_failure_code_spec.rb +2 -2
- data/spec/integration/{read_concern.rb → read_concern_spec.rb} +7 -1
- data/spec/integration/read_preference_spec.rb +485 -0
- data/spec/integration/retryable_writes_spec.rb +8 -19
- data/spec/integration/sdam_error_handling_spec.rb +1 -1
- data/spec/integration/sdam_events_spec.rb +2 -2
- data/spec/integration/server_description_spec.rb +14 -17
- data/spec/integration/server_selector_spec.rb +7 -3
- data/spec/integration/server_spec.rb +48 -0
- data/spec/integration/ssl_uri_options_spec.rb +1 -1
- data/spec/integration/step_down_spec.rb +10 -4
- data/spec/integration/transactions_examples_spec.rb +11 -10
- data/spec/lite_spec_helper.rb +19 -16
- data/spec/mongo/auth/scram/negotiation_spec.rb +11 -8
- data/spec/mongo/bulk_write/ordered_combiner_spec.rb +6 -6
- data/spec/mongo/bulk_write/unordered_combiner_spec.rb +4 -4
- data/spec/mongo/bulk_write_spec.rb +12 -2
- data/spec/mongo/client_construction_spec.rb +160 -8
- data/spec/mongo/client_spec.rb +5 -4
- data/spec/mongo/cluster_spec.rb +6 -6
- data/spec/mongo/cluster_time_spec.rb +148 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +34 -15
- data/spec/mongo/collection/view/change_stream_spec.rb +62 -3
- data/spec/mongo/collection/view/map_reduce_spec.rb +7 -5
- data/spec/mongo/collection/view/readable_spec.rb +4 -4
- data/spec/mongo/collection_spec.rb +331 -14
- data/spec/mongo/cursor_spec.rb +117 -5
- data/spec/mongo/database_spec.rb +240 -8
- data/spec/mongo/error/operation_failure_spec.rb +47 -1
- data/spec/mongo/error/parser_spec.rb +160 -23
- data/spec/mongo/operation/insert/bulk_spec.rb +2 -1
- data/spec/mongo/operation/result_spec.rb +27 -0
- data/spec/mongo/operation/update/bulk_spec.rb +1 -0
- data/spec/mongo/retryable_spec.rb +2 -0
- data/spec/mongo/server/app_metadata_spec.rb +2 -2
- data/spec/mongo/server/connection_spec.rb +13 -17
- data/spec/mongo/server/monitor/connection_spec.rb +13 -10
- data/spec/mongo/server_selector_spec.rb +34 -2
- data/spec/mongo/session/session_pool_spec.rb +14 -3
- data/spec/mongo/session_spec.rb +3 -3
- data/spec/mongo/session_transaction_spec.rb +4 -3
- data/spec/mongo/socket/ssl_spec.rb +19 -5
- data/spec/mongo/socket_spec.rb +1 -62
- data/spec/mongo/uri/srv_protocol_spec.rb +14 -20
- data/spec/mongo/uri_option_parsing_spec.rb +94 -8
- data/spec/mongo/uri_spec.rb +23 -10
- data/spec/mongo/write_concern_spec.rb +56 -3
- data/spec/spec_tests/change_streams_spec.rb +2 -1
- data/spec/spec_tests/cmap_spec.rb +1 -1
- data/spec/spec_tests/crud_spec.rb +12 -2
- data/spec/spec_tests/data/change_streams/change-streams-errors.yml +24 -1
- data/spec/spec_tests/data/change_streams/change-streams.yml +172 -3
- data/spec/spec_tests/data/command_monitoring/bulkWrite.yml +1 -1
- data/spec/spec_tests/data/command_monitoring/updateMany.yml +0 -2
- data/spec/spec_tests/data/command_monitoring/updateOne.yml +0 -5
- data/spec/spec_tests/data/crud/read/aggregate-out.yml +0 -6
- data/spec/spec_tests/data/crud/read/count-empty.yml +29 -0
- data/spec/spec_tests/data/crud/write/bulkWrite-arrayFilters.yml +1 -0
- data/spec/spec_tests/data/crud/write/bulkWrite-collation.yml +101 -0
- data/spec/spec_tests/data/crud/write/bulkWrite.yml +401 -0
- data/spec/spec_tests/data/crud/write/insertMany.yml +58 -2
- data/spec/spec_tests/data/crud/write/updateMany-arrayFilters.yml +3 -0
- data/spec/spec_tests/data/crud/write/updateOne-arrayFilters.yml +6 -1
- data/spec/spec_tests/data/crud_v2/aggregate-merge.yml +103 -0
- data/spec/spec_tests/data/crud_v2/aggregate-out-readConcern.yml +110 -0
- data/spec/spec_tests/data/crud_v2/bulkWrite-arrayFilters.yml +81 -0
- data/spec/spec_tests/data/crud_v2/db-aggregate.yml +38 -0
- data/spec/spec_tests/data/crud_v2/updateWithPipelines.yml +92 -0
- data/spec/spec_tests/data/retryable_writes/insertOne-serverErrors.yml +2 -2
- data/spec/spec_tests/data/transactions/abort.yml +3 -0
- data/spec/spec_tests/data/transactions/bulk.yml +3 -8
- data/spec/spec_tests/data/transactions/causal-consistency.yml +3 -8
- data/spec/spec_tests/data/transactions/commit.yml +3 -1
- data/spec/spec_tests/data/transactions/count.yml +3 -0
- data/spec/spec_tests/data/transactions/delete.yml +3 -0
- data/spec/spec_tests/data/transactions/error-labels.yml +4 -1
- data/spec/spec_tests/data/transactions/errors-client.yml +56 -0
- data/spec/spec_tests/data/transactions/errors.yml +3 -0
- data/spec/spec_tests/data/transactions/findOneAndDelete.yml +3 -0
- data/spec/spec_tests/data/transactions/findOneAndReplace.yml +3 -0
- data/spec/spec_tests/data/transactions/findOneAndUpdate.yml +3 -0
- data/spec/spec_tests/data/transactions/insert.yml +3 -0
- data/spec/spec_tests/data/transactions/isolation.yml +3 -0
- data/spec/spec_tests/data/transactions/mongos-pin-auto.yml +1671 -0
- data/spec/spec_tests/data/transactions/mongos-recovery-token.yml +347 -0
- data/spec/spec_tests/data/transactions/pin-mongos.yml +557 -0
- data/spec/spec_tests/data/transactions/read-concern.yml +3 -0
- data/spec/spec_tests/data/transactions/read-pref.yml +3 -0
- data/spec/spec_tests/data/transactions/reads.yml +3 -0
- data/spec/spec_tests/data/transactions/retryable-abort.yml +5 -2
- data/spec/spec_tests/data/transactions/retryable-commit.yml +4 -1
- data/spec/spec_tests/data/transactions/retryable-writes.yml +3 -0
- data/spec/spec_tests/data/transactions/run-command.yml +3 -0
- data/spec/spec_tests/data/transactions/transaction-options.yml +6 -0
- data/spec/spec_tests/data/transactions/update.yml +3 -8
- data/spec/spec_tests/data/transactions/write-concern.yml +348 -38
- data/spec/spec_tests/data/transactions_api/callback-aborts.yml +6 -0
- data/spec/spec_tests/data/transactions_api/callback-commits.yml +5 -0
- data/spec/spec_tests/data/transactions_api/callback-retry.yml +7 -2
- data/spec/spec_tests/data/transactions_api/commit-retry.yml +70 -15
- data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror-4.2.yml +3 -0
- data/spec/spec_tests/data/transactions_api/commit-transienttransactionerror.yml +3 -0
- data/spec/spec_tests/data/transactions_api/commit-writeconcernerror.yml +59 -109
- data/spec/spec_tests/data/transactions_api/commit.yml +5 -0
- data/spec/spec_tests/data/transactions_api/transaction-options.yml +10 -0
- data/spec/spec_tests/retryable_reads_spec.rb +5 -2
- data/spec/spec_tests/retryable_writes_spec.rb +5 -2
- data/spec/spec_tests/sdam_monitoring_spec.rb +3 -3
- data/spec/spec_tests/sdam_spec.rb +2 -2
- data/spec/spec_tests/transactions_api_spec.rb +1 -67
- data/spec/spec_tests/transactions_spec.rb +2 -66
- data/spec/support/authorization.rb +4 -0
- data/spec/support/change_streams.rb +30 -10
- data/spec/support/change_streams/operation.rb +27 -0
- data/spec/support/client_registry.rb +44 -25
- data/spec/support/cluster_config.rb +25 -14
- data/spec/support/cluster_tools.rb +32 -10
- data/spec/support/command_monitoring.rb +1 -1
- data/spec/support/common_shortcuts.rb +30 -0
- data/spec/support/connection_string.rb +8 -3
- data/spec/support/constraints.rb +34 -0
- data/spec/support/crud.rb +31 -16
- data/spec/support/crud/context.rb +23 -0
- data/spec/support/crud/operation.rb +311 -14
- data/spec/support/crud/spec.rb +2 -1
- data/spec/support/crud/test.rb +24 -27
- data/spec/support/crud/test_base.rb +22 -0
- data/spec/support/crud/verifier.rb +15 -1
- data/spec/support/event_subscriber.rb +12 -0
- data/spec/support/sdam_formatter_integration.rb +12 -6
- data/spec/support/shared/server_selector.rb +10 -0
- data/spec/support/shared/session.rb +13 -12
- data/spec/support/spec_config.rb +32 -22
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/transactions.rb +87 -0
- data/spec/support/transactions/context.rb +33 -0
- data/spec/support/transactions/operation.rb +99 -349
- data/spec/support/transactions/spec.rb +1 -3
- data/spec/support/transactions/test.rb +110 -49
- data/spec/support/utils.rb +74 -1
- metadata +52 -10
- metadata.gz.sig +0 -0
- data/spec/support/crud/read.rb +0 -265
- data/spec/support/crud/write.rb +0 -284
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Client' do
|
4
|
+
context 'after client is disconnected' do
|
5
|
+
let(:client) { authorized_client.with(server_selection_timeout: 1) }
|
6
|
+
|
7
|
+
before do
|
8
|
+
client.close
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'is still usable for operations' do
|
12
|
+
resp = client.database.command(ismaster: 1)
|
13
|
+
expect(resp).to be_a(Mongo::Operation::Result)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'is still usable for operations that can use sessions' do
|
17
|
+
client['collection'].insert_one(test: 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'after all servers are marked unknown' do
|
21
|
+
before do
|
22
|
+
client.cluster.servers.each do |server|
|
23
|
+
server.unknown!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'operation that never uses sessions' do
|
28
|
+
it 'fails server selection' do
|
29
|
+
expect do
|
30
|
+
client.database.command(ismaster: 1)
|
31
|
+
end.to raise_error(Mongo::Error::NoServerAvailable)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'operation that can use sessions' do
|
36
|
+
it 'fails server selection' do
|
37
|
+
expect do
|
38
|
+
client['collection'].insert_one(test: 1)
|
39
|
+
end.to raise_error(Mongo::Error::NoServerAvailable)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -61,7 +61,13 @@ describe 'Command' do
|
|
61
61
|
context 'with session' do
|
62
62
|
min_server_fcv '3.6'
|
63
63
|
|
64
|
-
let(:session)
|
64
|
+
let(:session) do
|
65
|
+
authorized_client.start_session.tap do |session|
|
66
|
+
# We are bypassing the normal transaction lifecycle, which would
|
67
|
+
# set txn_options
|
68
|
+
allow(session).to receive(:txn_options).and_return({})
|
69
|
+
end
|
70
|
+
end
|
65
71
|
|
66
72
|
let(:expected_payload) do
|
67
73
|
{
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# This test is a marker used to verify that the test suite runs on
|
4
|
+
# mmapv1 storage engine.
|
5
|
+
describe 'mmapv1' do
|
6
|
+
require_mmapv1
|
7
|
+
|
8
|
+
context 'standalone' do
|
9
|
+
require_topology :single
|
10
|
+
|
11
|
+
it 'is exercised' do
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'replica set' do
|
16
|
+
require_topology :replica_set
|
17
|
+
|
18
|
+
it 'is exercised' do
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'sharded' do
|
23
|
+
require_topology :sharded
|
24
|
+
|
25
|
+
it 'is exercised' do
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Mongos pinning' do
|
4
|
+
require_topology :sharded
|
5
|
+
min_server_fcv '4.2'
|
6
|
+
|
7
|
+
let(:client) { authorized_client }
|
8
|
+
let(:collection) { client['mongos_pinning_spec'] }
|
9
|
+
|
10
|
+
before do
|
11
|
+
collection.create
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'successful operations' do
|
15
|
+
it 'pins and unpins' do
|
16
|
+
session = client.start_session
|
17
|
+
expect(session.pinned_server).to be nil
|
18
|
+
|
19
|
+
session.start_transaction
|
20
|
+
expect(session.pinned_server).to be nil
|
21
|
+
|
22
|
+
primary = client.cluster.next_primary
|
23
|
+
|
24
|
+
collection.insert_one({a: 1}, session: session)
|
25
|
+
expect(session.pinned_server).not_to be nil
|
26
|
+
|
27
|
+
session.commit_transaction
|
28
|
+
expect(session.pinned_server).not_to be nil
|
29
|
+
|
30
|
+
collection.insert_one({a: 1}, session: session)
|
31
|
+
expect(session.pinned_server).to be nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -16,8 +16,8 @@ describe 'OperationFailure code' do
|
|
16
16
|
fail('Should have raised')
|
17
17
|
rescue Mongo::Error::OperationFailure => e
|
18
18
|
expect(e.code).to eq(11000)
|
19
|
-
# 4.0 and 4.
|
20
|
-
# 4.0 and 4.
|
19
|
+
# 4.0 and 4.2 sharded clusters set code name.
|
20
|
+
# 4.0 and 4.2 replica sets and standalones do not,
|
21
21
|
# and neither do older versions.
|
22
22
|
expect([nil, 'DuplicateKey']).to include(e.code_name)
|
23
23
|
end
|
@@ -1,11 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe 'read concern' do
|
4
|
+
min_server_version '3.2'
|
5
|
+
|
4
6
|
let(:subscriber) do
|
5
7
|
EventSubscriber.new
|
6
8
|
end
|
7
9
|
|
8
10
|
let(:specified_read_concern) do
|
11
|
+
{ :level => :local }
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:expected_read_concern) do
|
9
15
|
{ 'level' => 'local' }
|
10
16
|
end
|
11
17
|
|
@@ -17,7 +23,7 @@ describe 'read concern' do
|
|
17
23
|
|
18
24
|
shared_examples_for 'a read concern is specified' do
|
19
25
|
it 'sends a read concern to the server' do
|
20
|
-
expect(sent_read_concern).to eq(
|
26
|
+
expect(sent_read_concern).to eq(expected_read_concern)
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
@@ -0,0 +1,485 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# The only allowed read preference in transaction is primary.
|
4
|
+
# Because of this, the tests assert that the final read preference is primary.
|
5
|
+
# It would be preferable to assert that some other read preference is selected,
|
6
|
+
# but this would only work for non-transactional tests and would require
|
7
|
+
# duplicating the examples.
|
8
|
+
|
9
|
+
describe 'Read preference' do
|
10
|
+
clean_slate_on_evergreen
|
11
|
+
|
12
|
+
let(:client) do
|
13
|
+
authorized_client.with(client_options)
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:subscriber) { EventSubscriber.new }
|
17
|
+
|
18
|
+
before do
|
19
|
+
client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:client_options) do
|
23
|
+
{}
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:session_options) do
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:tx_options) do
|
31
|
+
{}
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:collection) { client['tx_read_pref_test'] }
|
35
|
+
|
36
|
+
before do
|
37
|
+
collection.drop
|
38
|
+
collection.create(write_concern: {w: :majority})
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:find_options) do
|
42
|
+
{}
|
43
|
+
end
|
44
|
+
|
45
|
+
shared_examples_for 'sends expected read preference when reading' do
|
46
|
+
it 'sends expected read preference when reading' do
|
47
|
+
read_operation
|
48
|
+
|
49
|
+
event = subscriber.single_command_started_event('find')
|
50
|
+
actual_preference = event.command['$readPreference']
|
51
|
+
expect(actual_preference).to eq(expected_read_preference)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
shared_examples_for 'does not send read preference when reading' do
|
56
|
+
it 'does not send read preference when reading' do
|
57
|
+
read_operation
|
58
|
+
|
59
|
+
event = subscriber.single_command_started_event('find')
|
60
|
+
actual_preference = event.command['$readPreference']
|
61
|
+
expect(actual_preference).to be nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
shared_examples_for 'non-transactional read preference examples' do
|
66
|
+
it 'does not send read preference when writing' do
|
67
|
+
write_operation
|
68
|
+
|
69
|
+
event = subscriber.single_command_started_event('insert')
|
70
|
+
actual_preference = event.command['$readPreference']
|
71
|
+
expect(actual_preference).to be nil
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'standalone' do
|
75
|
+
require_topology :single
|
76
|
+
|
77
|
+
it_behaves_like 'does not send read preference when reading'
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'RS, sharded cluster' do
|
81
|
+
# Supposedly read preference should only be sent in a sharded cluster
|
82
|
+
# topology. However, transactions spec tests contain read preference
|
83
|
+
# assertions also when they are run in RS topologies.
|
84
|
+
require_topology :sharded, :replica_set
|
85
|
+
|
86
|
+
context 'pre-OP_MSG server' do
|
87
|
+
max_server_version '3.4'
|
88
|
+
|
89
|
+
it_behaves_like 'does not send read preference when reading'
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'server supporting OP_MSG' do
|
93
|
+
min_server_fcv '3.6'
|
94
|
+
|
95
|
+
it_behaves_like 'sends expected read preference when reading'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
shared_examples_for 'sends expected read preference' do
|
101
|
+
it_behaves_like 'non-transactional read preference examples'
|
102
|
+
end
|
103
|
+
|
104
|
+
shared_context 'non-transactional read preference specifications' do
|
105
|
+
|
106
|
+
context 'when read preference is not explicitly given' do
|
107
|
+
let(:client_options) do
|
108
|
+
{}
|
109
|
+
end
|
110
|
+
|
111
|
+
let(:expected_read_preference) do
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
|
115
|
+
it_behaves_like 'sends expected read preference'
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'when read preference is given in client options' do
|
119
|
+
let(:client_options) do
|
120
|
+
{read: { mode: :primary }}
|
121
|
+
end
|
122
|
+
|
123
|
+
let(:expected_read_preference) do
|
124
|
+
{'mode' => 'primary'}
|
125
|
+
end
|
126
|
+
|
127
|
+
it_behaves_like 'sends expected read preference'
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when read preference is given in operation options' do
|
131
|
+
let(:expected_read_preference) do
|
132
|
+
{'mode' => 'primary'}
|
133
|
+
end
|
134
|
+
|
135
|
+
let(:find_options) do
|
136
|
+
{read: {mode: :primary}}
|
137
|
+
end
|
138
|
+
|
139
|
+
it_behaves_like 'sends expected read preference'
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when read preference is given in client and operation options' do
|
143
|
+
let(:client_options) do
|
144
|
+
{read: { mode: :secondary }}
|
145
|
+
end
|
146
|
+
|
147
|
+
# Operation should override the client.
|
148
|
+
let(:expected_read_preference) do
|
149
|
+
{'mode' => 'primary'}
|
150
|
+
end
|
151
|
+
|
152
|
+
let(:find_options) do
|
153
|
+
{read: {mode: :primary}}
|
154
|
+
end
|
155
|
+
|
156
|
+
it_behaves_like 'sends expected read preference'
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'when read preference is given in collection and operation options' do
|
160
|
+
let(:collection) do
|
161
|
+
client['tx_read_pref_test', {read: {mode: :secondary}}]
|
162
|
+
end
|
163
|
+
|
164
|
+
# Operation should override the collection.
|
165
|
+
let(:expected_read_preference) do
|
166
|
+
{'mode' => 'primary'}
|
167
|
+
end
|
168
|
+
|
169
|
+
let(:find_options) do
|
170
|
+
{read: {mode: :primary}}
|
171
|
+
end
|
172
|
+
|
173
|
+
it_behaves_like 'sends expected read preference'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'not in transaction' do
|
178
|
+
|
179
|
+
let(:write_operation) do
|
180
|
+
collection.insert_one(hello: 'world')
|
181
|
+
end
|
182
|
+
|
183
|
+
let(:read_operation) do
|
184
|
+
collection.with(write: {w: :majority}).insert_one(hello: 'world')
|
185
|
+
res = collection.find({}, find_options || {}).to_a.count
|
186
|
+
expect(res).to eq(1)
|
187
|
+
end
|
188
|
+
|
189
|
+
include_context 'non-transactional read preference specifications'
|
190
|
+
|
191
|
+
context 'when read preference is given in collection options' do
|
192
|
+
let(:client_options) do
|
193
|
+
{}
|
194
|
+
end
|
195
|
+
|
196
|
+
let(:collection) do
|
197
|
+
client['tx_read_pref_test', {read: {mode: :primary}}]
|
198
|
+
end
|
199
|
+
|
200
|
+
let(:expected_read_preference) do
|
201
|
+
{'mode' => 'primary'}
|
202
|
+
end
|
203
|
+
|
204
|
+
it_behaves_like 'sends expected read preference'
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when read preference is given in collection options via #with' do
|
208
|
+
let(:collection) do
|
209
|
+
client['tx_read_pref_test'].with(read: {mode: :primary})
|
210
|
+
end
|
211
|
+
|
212
|
+
let(:expected_read_preference) do
|
213
|
+
{'mode' => 'primary'}
|
214
|
+
end
|
215
|
+
|
216
|
+
it_behaves_like 'sends expected read preference'
|
217
|
+
end
|
218
|
+
|
219
|
+
context 'when read preference is given in client and collection options' do
|
220
|
+
let(:client_options) do
|
221
|
+
{read: { mode: :secondary }}
|
222
|
+
end
|
223
|
+
|
224
|
+
let(:collection) do
|
225
|
+
client['tx_read_pref_test', {read: {mode: :primary}}]
|
226
|
+
end
|
227
|
+
|
228
|
+
# Collection should override the client.
|
229
|
+
let(:expected_read_preference) do
|
230
|
+
{'mode' => 'primary'}
|
231
|
+
end
|
232
|
+
|
233
|
+
it_behaves_like 'sends expected read preference'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'in transaction' do
|
238
|
+
# 4.0/RS is a valid topology to test against, but our tooling doesn't
|
239
|
+
# support multiple constraint specifications like runOn does.
|
240
|
+
# There is no loss of generality to constrain these tests to 4.2+.
|
241
|
+
min_server_fcv '4.2'
|
242
|
+
require_topology :sharded, :replica_set
|
243
|
+
|
244
|
+
let(:write_operation) do
|
245
|
+
expect do
|
246
|
+
session = client.start_session(session_options)
|
247
|
+
session.with_transaction(tx_options) do
|
248
|
+
collection.insert_one({hello: 'world'}, session: session)
|
249
|
+
end
|
250
|
+
end.not_to raise_error
|
251
|
+
end
|
252
|
+
|
253
|
+
let(:read_operation) do
|
254
|
+
expect do
|
255
|
+
session = client.start_session(session_options)
|
256
|
+
session.with_transaction(tx_options) do
|
257
|
+
collection.insert_one({hello: 'world'}, session: session)
|
258
|
+
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
259
|
+
expect(res).to eq(1)
|
260
|
+
end
|
261
|
+
end.not_to raise_error
|
262
|
+
end
|
263
|
+
|
264
|
+
shared_examples_for 'sends expected read preference' do
|
265
|
+
it_behaves_like 'non-transactional read preference examples'
|
266
|
+
|
267
|
+
it 'sends expected read preference when starting transaction' do
|
268
|
+
collection.insert_one(hello: 'world')
|
269
|
+
|
270
|
+
session = client.start_session(session_options)
|
271
|
+
session.with_transaction(tx_options) do
|
272
|
+
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
273
|
+
expect(res).to eq(1)
|
274
|
+
end
|
275
|
+
|
276
|
+
event = subscriber.single_command_started_event('find')
|
277
|
+
actual_preference = event.command['$readPreference']
|
278
|
+
expect(actual_preference).to eq(expected_read_preference)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
include_context 'non-transactional read preference specifications'
|
283
|
+
|
284
|
+
context 'when read preference is given in collection options' do
|
285
|
+
let(:client_options) do
|
286
|
+
{}
|
287
|
+
end
|
288
|
+
|
289
|
+
let(:collection) do
|
290
|
+
client['tx_read_pref_test', {read: {mode: :primary}}]
|
291
|
+
end
|
292
|
+
|
293
|
+
# collection read preference is ignored
|
294
|
+
let(:expected_read_preference) do
|
295
|
+
nil
|
296
|
+
end
|
297
|
+
|
298
|
+
it_behaves_like 'sends expected read preference'
|
299
|
+
end
|
300
|
+
|
301
|
+
context 'when read preference is given in collection options via #with' do
|
302
|
+
let(:collection) do
|
303
|
+
client['tx_read_pref_test'].with(read: {mode: :primary})
|
304
|
+
end
|
305
|
+
|
306
|
+
# collection read preference is ignored
|
307
|
+
let(:expected_read_preference) do
|
308
|
+
nil
|
309
|
+
end
|
310
|
+
|
311
|
+
it_behaves_like 'sends expected read preference'
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'when read preference is given in client and collection options' do
|
315
|
+
let(:client_options) do
|
316
|
+
{read: { mode: :primary }}
|
317
|
+
end
|
318
|
+
|
319
|
+
let(:collection) do
|
320
|
+
client['tx_read_pref_test', {read: {mode: :secondary}}]
|
321
|
+
end
|
322
|
+
|
323
|
+
# collection read preference is ignored, client read preference is used
|
324
|
+
let(:expected_read_preference) do
|
325
|
+
{'mode' => 'primary'}
|
326
|
+
end
|
327
|
+
|
328
|
+
it_behaves_like 'sends expected read preference'
|
329
|
+
end
|
330
|
+
|
331
|
+
context 'when read preference is given in default transaction options' do
|
332
|
+
let(:session_options) do
|
333
|
+
{default_transaction_options: {read: { mode: :primary }}}
|
334
|
+
end
|
335
|
+
|
336
|
+
let(:expected_read_preference) do
|
337
|
+
{'mode' => 'primary'}
|
338
|
+
end
|
339
|
+
|
340
|
+
it_behaves_like 'sends expected read preference'
|
341
|
+
end
|
342
|
+
|
343
|
+
context 'when read preference is given in client and default transaction options' do
|
344
|
+
let(:client_options) do
|
345
|
+
{read: { mode: :secondary }}
|
346
|
+
end
|
347
|
+
|
348
|
+
let(:session_options) do
|
349
|
+
{default_transaction_options: {read: { mode: :primary }}}
|
350
|
+
end
|
351
|
+
|
352
|
+
let(:expected_read_preference) do
|
353
|
+
{'mode' => 'primary'}
|
354
|
+
end
|
355
|
+
|
356
|
+
it_behaves_like 'sends expected read preference'
|
357
|
+
end
|
358
|
+
|
359
|
+
context 'when read preference is given in collection and default transaction options' do
|
360
|
+
let(:collection) do
|
361
|
+
client['tx_read_pref_test', {read: {mode: :secondary}}]
|
362
|
+
end
|
363
|
+
|
364
|
+
let(:session_options) do
|
365
|
+
{default_transaction_options: {read: { mode: :primary }}}
|
366
|
+
end
|
367
|
+
|
368
|
+
let(:expected_read_preference) do
|
369
|
+
{'mode' => 'primary'}
|
370
|
+
end
|
371
|
+
|
372
|
+
it_behaves_like 'sends expected read preference'
|
373
|
+
end
|
374
|
+
|
375
|
+
context 'when read preference is given in default transaction and transaction options' do
|
376
|
+
let(:session_options) do
|
377
|
+
{default_transaction_options: {read: { mode: :secondary }}}
|
378
|
+
end
|
379
|
+
|
380
|
+
let(:tx_options) do
|
381
|
+
{read: { mode: :primary }}
|
382
|
+
end
|
383
|
+
|
384
|
+
let(:expected_read_preference) do
|
385
|
+
{'mode' => 'primary'}
|
386
|
+
end
|
387
|
+
|
388
|
+
it_behaves_like 'sends expected read preference'
|
389
|
+
end
|
390
|
+
|
391
|
+
context 'when read preference is given in default transaction and operation options' do
|
392
|
+
let(:session_options) do
|
393
|
+
{default_transaction_options: {read: { mode: :primary }}}
|
394
|
+
end
|
395
|
+
|
396
|
+
let(:find_options) do
|
397
|
+
{read: {mode: :secondary}}
|
398
|
+
end
|
399
|
+
|
400
|
+
let(:expected_read_preference) do
|
401
|
+
{'mode' => 'primary'}
|
402
|
+
end
|
403
|
+
|
404
|
+
it 'sends operation read preference and fails' do
|
405
|
+
expect do
|
406
|
+
session = client.start_session(session_options)
|
407
|
+
session.with_transaction(tx_options) do
|
408
|
+
collection.insert_one({hello: 'world'}, session: session)
|
409
|
+
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
410
|
+
expect(res).to eq(1)
|
411
|
+
end
|
412
|
+
end.to raise_error(Mongo::Error::InvalidTransactionOperation, "read preference in a transaction must be primary (requested: secondary)")
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context 'when read preference is given in transaction options' do
|
417
|
+
let(:tx_options) do
|
418
|
+
{read: { mode: :primary }}
|
419
|
+
end
|
420
|
+
|
421
|
+
let(:expected_read_preference) do
|
422
|
+
{'mode' => 'primary'}
|
423
|
+
end
|
424
|
+
|
425
|
+
it_behaves_like 'sends expected read preference'
|
426
|
+
end
|
427
|
+
|
428
|
+
context 'when read preference is given in client and transaction options' do
|
429
|
+
let(:client_options) do
|
430
|
+
{read: { mode: :secondary }}
|
431
|
+
end
|
432
|
+
|
433
|
+
let(:tx_options) do
|
434
|
+
{read: { mode: :primary }}
|
435
|
+
end
|
436
|
+
|
437
|
+
let(:expected_read_preference) do
|
438
|
+
{'mode' => 'primary'}
|
439
|
+
end
|
440
|
+
|
441
|
+
it_behaves_like 'sends expected read preference'
|
442
|
+
end
|
443
|
+
|
444
|
+
context 'when read preference is given in collection and transaction options' do
|
445
|
+
let(:collection) do
|
446
|
+
client['tx_read_pref_test', {read: {mode: :secondary}}]
|
447
|
+
end
|
448
|
+
|
449
|
+
let(:tx_options) do
|
450
|
+
{read: { mode: :primary }}
|
451
|
+
end
|
452
|
+
|
453
|
+
let(:expected_read_preference) do
|
454
|
+
{'mode' => 'primary'}
|
455
|
+
end
|
456
|
+
|
457
|
+
it_behaves_like 'sends expected read preference'
|
458
|
+
end
|
459
|
+
|
460
|
+
context 'when read preference is given in transaction and operation options' do
|
461
|
+
let(:tx_options) do
|
462
|
+
{read: { mode: :primary }}
|
463
|
+
end
|
464
|
+
|
465
|
+
let(:find_options) do
|
466
|
+
{read: {mode: :secondary}}
|
467
|
+
end
|
468
|
+
|
469
|
+
let(:expected_read_preference) do
|
470
|
+
{'mode' => 'primary'}
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'sends operation read preference and fails' do
|
474
|
+
expect do
|
475
|
+
session = client.start_session(session_options)
|
476
|
+
session.with_transaction(tx_options) do
|
477
|
+
collection.insert_one({hello: 'world'}, session: session)
|
478
|
+
res = collection.find({}, {session: session}.merge(find_options || {})).to_a.count
|
479
|
+
expect(res).to eq(1)
|
480
|
+
end
|
481
|
+
end.to raise_error(Mongo::Error::InvalidTransactionOperation, "read preference in a transaction must be primary (requested: secondary)")
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
end
|