mongo 2.4.3 → 2.5.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -2
- data.tar.gz.sig +0 -0
- data/lib/mongo.rb +3 -2
- data/lib/mongo/auth/cr.rb +6 -4
- data/lib/mongo/auth/cr/conversation.rb +33 -17
- data/lib/mongo/auth/ldap.rb +4 -2
- data/lib/mongo/auth/ldap/conversation.rb +19 -9
- data/lib/mongo/auth/scram.rb +7 -4
- data/lib/mongo/auth/scram/conversation.rb +62 -24
- data/lib/mongo/auth/user.rb +10 -0
- data/lib/mongo/auth/user/view.rb +44 -22
- data/lib/mongo/auth/x509.rb +4 -2
- data/lib/mongo/auth/x509/conversation.rb +19 -9
- data/lib/mongo/bulk_write.rb +33 -27
- data/lib/mongo/bulk_write/combineable.rb +5 -0
- data/lib/mongo/bulk_write/transformable.rb +2 -0
- data/lib/mongo/bulk_write/validatable.rb +4 -0
- data/lib/mongo/client.rb +123 -12
- data/lib/mongo/cluster.rb +52 -11
- data/lib/mongo/cluster/app_metadata.rb +8 -2
- data/lib/mongo/cluster/cursor_reaper.rb +0 -1
- data/lib/mongo/cluster/topology.rb +1 -1
- data/lib/mongo/collection.rb +114 -27
- data/lib/mongo/collection/view.rb +8 -2
- data/lib/mongo/collection/view/aggregation.rb +11 -7
- data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
- data/lib/mongo/collection/view/builder/find_command.rb +5 -3
- data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
- data/lib/mongo/collection/view/builder/op_query.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +160 -0
- data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
- data/lib/mongo/collection/view/iterable.rb +11 -10
- data/lib/mongo/collection/view/map_reduce.rb +22 -18
- data/lib/mongo/collection/view/readable.rb +51 -37
- data/lib/mongo/collection/view/writable.rb +72 -40
- data/lib/mongo/cursor.rb +25 -4
- data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
- data/lib/mongo/database.rb +22 -11
- data/lib/mongo/database/view.rb +16 -12
- data/lib/mongo/error.rb +5 -0
- data/lib/mongo/error/invalid_session.rb +36 -0
- data/lib/mongo/error/missing_resume_token.rb +39 -0
- data/lib/mongo/error/operation_failure.rb +17 -0
- data/lib/mongo/error/parser.rb +3 -2
- data/lib/mongo/error/unknown_payload_type.rb +41 -0
- data/lib/mongo/error/unsupported_array_filters.rb +51 -0
- data/lib/mongo/error/unsupported_message_type.rb +23 -0
- data/lib/mongo/grid/fs_bucket.rb +5 -4
- data/lib/mongo/grid/stream/read.rb +3 -2
- data/lib/mongo/grid/stream/write.rb +2 -2
- data/lib/mongo/index/view.rb +35 -25
- data/lib/mongo/monitoring/event/secure.rb +14 -0
- data/lib/mongo/operation.rb +16 -0
- data/lib/mongo/operation/commands.rb +1 -0
- data/lib/mongo/operation/commands/aggregate.rb +9 -5
- data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
- data/lib/mongo/operation/commands/collections_info.rb +6 -6
- data/lib/mongo/operation/commands/command.rb +2 -1
- data/lib/mongo/operation/commands/create.rb +6 -2
- data/lib/mongo/operation/commands/drop.rb +6 -2
- data/lib/mongo/operation/commands/drop_database.rb +6 -2
- data/lib/mongo/operation/commands/explain.rb +27 -0
- data/lib/mongo/operation/commands/explain/result.rb +52 -0
- data/lib/mongo/operation/commands/indexes.rb +1 -1
- data/lib/mongo/operation/commands/list_collections.rb +1 -1
- data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
- data/lib/mongo/operation/commands/list_indexes.rb +1 -1
- data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
- data/lib/mongo/operation/commands/map_reduce.rb +8 -4
- data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
- data/lib/mongo/operation/commands/user_query.rb +1 -1
- data/lib/mongo/operation/commands/users_info.rb +6 -2
- data/lib/mongo/operation/executable.rb +4 -1
- data/lib/mongo/operation/read_preference.rb +10 -5
- data/lib/mongo/operation/result.rb +26 -2
- data/lib/mongo/operation/specifiable.rb +13 -1
- data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
- data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
- data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
- data/lib/mongo/operation/write/command/create_index.rb +6 -1
- data/lib/mongo/operation/write/command/delete.rb +28 -4
- data/lib/mongo/operation/write/command/drop_index.rb +6 -1
- data/lib/mongo/operation/write/command/insert.rb +22 -18
- data/lib/mongo/operation/write/command/update.rb +24 -9
- data/lib/mongo/operation/write/command/writable.rb +14 -1
- data/lib/mongo/operation/write/insert.rb +4 -1
- data/lib/mongo/operation/write/insert/result.rb +2 -2
- data/lib/mongo/operation/write/update.rb +7 -1
- data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
- data/lib/mongo/protocol.rb +3 -0
- data/lib/mongo/protocol/bit_vector.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +135 -0
- data/lib/mongo/protocol/delete.rb +8 -6
- data/lib/mongo/protocol/get_more.rb +8 -6
- data/lib/mongo/protocol/insert.rb +8 -6
- data/lib/mongo/protocol/kill_cursors.rb +8 -6
- data/lib/mongo/protocol/message.rb +31 -3
- data/lib/mongo/protocol/msg.rb +172 -0
- data/lib/mongo/protocol/query.rb +26 -6
- data/lib/mongo/protocol/registry.rb +76 -0
- data/lib/mongo/protocol/reply.rb +10 -5
- data/lib/mongo/protocol/serializers.rb +224 -0
- data/lib/mongo/protocol/update.rb +8 -6
- data/lib/mongo/retryable.rb +4 -2
- data/lib/mongo/server.rb +6 -3
- data/lib/mongo/server/connectable.rb +1 -1
- data/lib/mongo/server/connection.rb +30 -8
- data/lib/mongo/server/description.rb +25 -1
- data/lib/mongo/server/description/features.rb +4 -1
- data/lib/mongo/server/monitor.rb +5 -0
- data/lib/mongo/server/monitor/connection.rb +50 -2
- data/lib/mongo/server_selector/nearest.rb +10 -4
- data/lib/mongo/server_selector/primary.rb +20 -0
- data/lib/mongo/server_selector/primary_preferred.rb +10 -4
- data/lib/mongo/server_selector/secondary.rb +10 -4
- data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
- data/lib/mongo/session.rb +180 -0
- data/lib/mongo/session/server_session.rb +73 -0
- data/lib/mongo/session/session_pool.rb +161 -0
- data/lib/mongo/uri.rb +11 -0
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +2 -1
- data/spec/mongo/auth/cr_spec.rb +12 -0
- data/spec/mongo/auth/ldap_spec.rb +2 -0
- data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
- data/spec/mongo/auth/scram_spec.rb +25 -1
- data/spec/mongo/auth/user/view_spec.rb +268 -76
- data/spec/mongo/auth/x509_spec.rb +2 -0
- data/spec/mongo/bulk_write_spec.rb +435 -5
- data/spec/mongo/client_spec.rb +356 -39
- data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
- data/spec/mongo/cluster_spec.rb +176 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
- data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
- data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
- data/spec/mongo/collection/view/readable_spec.rb +3 -12
- data/spec/mongo/collection_spec.rb +1048 -42
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
- data/spec/mongo/cursor_spec.rb +2 -2
- data/spec/mongo/database_spec.rb +50 -1
- data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
- data/spec/mongo/grid/stream/read_spec.rb +2 -2
- data/spec/mongo/index/view_spec.rb +146 -8
- data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
- data/spec/mongo/operation/read/query_spec.rb +2 -1
- data/spec/mongo/operation/specifiable_spec.rb +2 -2
- data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
- data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
- data/spec/mongo/operation/write/command/update_spec.rb +93 -10
- data/spec/mongo/operation/write/delete_spec.rb +1 -1
- data/spec/mongo/operation/write/insert_spec.rb +1 -1
- data/spec/mongo/operation/write/update_spec.rb +1 -1
- data/spec/mongo/protocol/compressed_spec.rb +66 -0
- data/spec/mongo/protocol/delete_spec.rb +14 -0
- data/spec/mongo/protocol/get_more_spec.rb +14 -0
- data/spec/mongo/protocol/insert_spec.rb +14 -0
- data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
- data/spec/mongo/protocol/msg_spec.rb +499 -0
- data/spec/mongo/protocol/query_spec.rb +45 -0
- data/spec/mongo/protocol/registry_spec.rb +31 -0
- data/spec/mongo/protocol/reply_spec.rb +14 -0
- data/spec/mongo/protocol/update_spec.rb +14 -0
- data/spec/mongo/retryable_spec.rb +6 -2
- data/spec/mongo/sdam_spec.rb +4 -0
- data/spec/mongo/server/connection_spec.rb +4 -2
- data/spec/mongo/server/description_spec.rb +28 -1
- data/spec/mongo/session/server_session_spec.rb +16 -0
- data/spec/mongo/session/session_pool_spec.rb +194 -0
- data/spec/mongo/uri_spec.rb +31 -2
- data/spec/spec_helper.rb +104 -0
- data/spec/support/authorization.rb +6 -1
- data/spec/support/crud.rb +3 -1
- data/spec/support/crud/write.rb +6 -1
- data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
- data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
- data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
- data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
- data/spec/support/sdam/rs/discover_passives.yml +2 -2
- data/spec/support/sdam/rs/discover_primary.yml +1 -1
- data/spec/support/sdam/rs/discover_secondary.yml +1 -1
- data/spec/support/sdam/rs/discovery.yml +4 -4
- data/spec/support/sdam/rs/equal_electionids.yml +1 -0
- data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
- data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
- data/spec/support/sdam/rs/ls_timeout.yml +88 -0
- data/spec/support/sdam/rs/member_reconfig.yml +2 -2
- data/spec/support/sdam/rs/member_standalone.yml +2 -2
- data/spec/support/sdam/rs/new_primary.yml +2 -2
- data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
- data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
- data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
- data/spec/support/sdam/rs/non_rs_member.yml +1 -1
- data/spec/support/sdam/rs/normalize_case.yml +1 -1
- data/spec/support/sdam/rs/null_election_id.yml +4 -0
- data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
- data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
- data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
- data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
- data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
- data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
- data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
- data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
- data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
- data/spec/support/sdam/rs/response_from_removed.yml +2 -2
- data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
- data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
- data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
- data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
- data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
- data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
- data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
- data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
- data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
- data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
- data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
- data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
- data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
- data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
- data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
- data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
- data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
- data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
- data/spec/support/sdam/single/not_ok_response.yml +1 -1
- data/spec/support/sdam/single/standalone_removed.yml +1 -1
- data/spec/support/sdam/single/unavailable_seed.yml +1 -1
- data/spec/support/server_discovery_and_monitoring.rb +4 -0
- data/spec/support/shared/session.rb +236 -0
- metadata +53 -15
- metadata.gz.sig +0 -0
@@ -93,18 +93,101 @@ describe Mongo::Operation::Write::Command::Update do
|
|
93
93
|
|
94
94
|
describe '#message' do
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
96
|
+
context 'when the server supports OP_MSG', if: op_msg_enabled? do
|
97
|
+
|
98
|
+
let(:global_args) do
|
99
|
+
{
|
100
|
+
update: TEST_COLL,
|
101
|
+
ordered: true,
|
102
|
+
writeConcern: write_concern.options,
|
103
|
+
'$db' => TEST_DB
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:expected_payload_1) do
|
108
|
+
{
|
109
|
+
type: 1,
|
110
|
+
payload: { identifier: 'updates',
|
111
|
+
sequence: updates
|
112
|
+
}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when the topology is sharded', if: sharded? && op_msg_enabled? do
|
117
|
+
|
118
|
+
let(:expected_global_args) do
|
119
|
+
global_args.merge(Mongo::Operation::CLUSTER_TIME => authorized_client.cluster.cluster_time)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'creates the correct OP_MSG message' do
|
123
|
+
authorized_client.command(ping:1)
|
124
|
+
expect(Mongo::Protocol::Msg).to receive(:new).with([:none], {}, expected_global_args, expected_payload_1)
|
125
|
+
op.send(:message, authorized_primary)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'when the topology is not sharded', if: !sharded? && op_msg_enabled? do
|
130
|
+
|
131
|
+
let(:expected_global_args) do
|
132
|
+
global_args
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'creates the correct OP_MSG message' do
|
136
|
+
authorized_client.command(ping:1)
|
137
|
+
expect(Mongo::Protocol::Msg).to receive(:new).with([:none], {}, expected_global_args, expected_payload_1)
|
138
|
+
op.send(:message, authorized_primary)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when the write concern is 0' do
|
143
|
+
|
144
|
+
let(:write_concern) do
|
145
|
+
Mongo::WriteConcern.get(w: 0)
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'when the topology is sharded', if: sharded? && op_msg_enabled? do
|
149
|
+
|
150
|
+
let(:expected_global_args) do
|
151
|
+
global_args.merge(Mongo::Operation::CLUSTER_TIME => authorized_client.cluster.cluster_time)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'creates the correct OP_MSG message' do
|
155
|
+
authorized_client.command(ping:1)
|
156
|
+
expect(Mongo::Protocol::Msg).to receive(:new).with([:more_to_come], {}, expected_global_args, expected_payload_1)
|
157
|
+
op.send(:message, authorized_primary)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when the topology is not sharded', if: !sharded? && op_msg_enabled? do
|
162
|
+
|
163
|
+
let(:expected_global_args) do
|
164
|
+
global_args
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'creates the correct OP_MSG message' do
|
168
|
+
authorized_client.command(ping:1)
|
169
|
+
expect(Mongo::Protocol::Msg).to receive(:new).with([:more_to_come], {}, expected_global_args, expected_payload_1)
|
170
|
+
op.send(:message, authorized_primary)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
103
174
|
end
|
104
175
|
|
105
|
-
|
106
|
-
|
107
|
-
|
176
|
+
context 'when the server does not support OP_MSG' do
|
177
|
+
|
178
|
+
let(:expected_selector) do
|
179
|
+
{
|
180
|
+
:update => TEST_COLL,
|
181
|
+
:updates => updates,
|
182
|
+
:ordered => true,
|
183
|
+
:writeConcern => write_concern.options
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'creates the correct Command message', unless: op_msg_enabled? do
|
188
|
+
expect(Mongo::Protocol::Query).to receive(:new).with(TEST_DB, '$cmd', expected_selector, { limit: -1 })
|
189
|
+
op.send(:message, authorized_primary)
|
190
|
+
end
|
108
191
|
end
|
109
192
|
end
|
110
193
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongo::Protocol::Compressed do
|
4
|
+
|
5
|
+
let(:original_message) { Mongo::Protocol::Query.new(TEST_DB, TEST_COLL, { ping: 1 }) }
|
6
|
+
let(:compressor) { 'zlib' }
|
7
|
+
let(:level) { nil }
|
8
|
+
|
9
|
+
let(:message) do
|
10
|
+
described_class.new(original_message, compressor, level)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#serialize' do
|
14
|
+
|
15
|
+
context 'when zlib compression level is not provided' do
|
16
|
+
|
17
|
+
let(:original_message_bytes) do
|
18
|
+
buf = BSON::ByteBuffer.new
|
19
|
+
original_message.send(:serialize_fields, buf)
|
20
|
+
buf.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'does not set a compression level' do
|
24
|
+
expect(Zlib::Deflate).to receive(:deflate).with(original_message_bytes, nil).and_call_original
|
25
|
+
message.serialize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when zlib compression level is provided' do
|
30
|
+
|
31
|
+
let(:level) { 1 }
|
32
|
+
|
33
|
+
let(:original_message_bytes) do
|
34
|
+
buf = BSON::ByteBuffer.new
|
35
|
+
original_message.send(:serialize_fields, buf)
|
36
|
+
buf.to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'uses the compression level' do
|
40
|
+
expect(Zlib::Deflate).to receive(:deflate).with(original_message_bytes, 1).and_call_original
|
41
|
+
message.serialize
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#replyable?' do
|
47
|
+
|
48
|
+
context 'when the original message is replyable' do
|
49
|
+
|
50
|
+
it 'returns true' do
|
51
|
+
expect(message.replyable?).to be(true)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when the original message is not replyable', if: op_msg_enabled? do
|
56
|
+
|
57
|
+
let(:original_message) do
|
58
|
+
Mongo::Protocol::Msg.new([:more_to_come], {}, { ping: 1 })
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns false' do
|
62
|
+
expect(message.replyable?).to be(false)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -164,4 +164,18 @@ describe Mongo::Protocol::Delete do
|
|
164
164
|
end
|
165
165
|
end
|
166
166
|
end
|
167
|
+
|
168
|
+
describe '#registry' do
|
169
|
+
|
170
|
+
context 'when the class is loaded' do
|
171
|
+
|
172
|
+
it 'registers the op code in the Protocol Registry' do
|
173
|
+
expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'creates an #op_code instance method' do
|
177
|
+
expect(message.op_code).to eq(described_class::OP_CODE)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
167
181
|
end
|
@@ -143,4 +143,18 @@ describe Mongo::Protocol::GetMore do
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
end
|
146
|
+
|
147
|
+
describe '#registry' do
|
148
|
+
|
149
|
+
context 'when the class is loaded' do
|
150
|
+
|
151
|
+
it 'registers the op code in the Protocol Registry' do
|
152
|
+
expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'creates an #op_code instance method' do
|
156
|
+
expect(message.op_code).to eq(described_class::OP_CODE)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
146
160
|
end
|
@@ -158,4 +158,18 @@ describe Mongo::Protocol::Insert do
|
|
158
158
|
end
|
159
159
|
end
|
160
160
|
end
|
161
|
+
|
162
|
+
describe '#registry' do
|
163
|
+
|
164
|
+
context 'when the class is loaded' do
|
165
|
+
|
166
|
+
it 'registers the op code in the Protocol Registry' do
|
167
|
+
expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'creates an #op_code instance method' do
|
171
|
+
expect(message.op_code).to eq(described_class::OP_CODE)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
161
175
|
end
|
@@ -100,4 +100,18 @@ describe Mongo::Protocol::KillCursors do
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
103
|
+
|
104
|
+
describe '#registry' do
|
105
|
+
|
106
|
+
context 'when the class is loaded' do
|
107
|
+
|
108
|
+
it 'registers the op code in the Protocol Registry' do
|
109
|
+
expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'creates an #op_code instance method' do
|
113
|
+
expect(message.op_code).to eq(described_class::OP_CODE)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
103
117
|
end
|
@@ -0,0 +1,499 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongo::Protocol::Msg do
|
4
|
+
|
5
|
+
let(:opcode) { 2013 }
|
6
|
+
let(:flags) { [:none] }
|
7
|
+
let(:options) { {} }
|
8
|
+
let(:global_args) { { '$db' => TEST_DB, ping: 1 } }
|
9
|
+
let(:sections) { [ ] }
|
10
|
+
|
11
|
+
let(:message) do
|
12
|
+
described_class.new(flags, options, global_args, *sections)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:deserialized) do
|
16
|
+
Mongo::Protocol::Message.deserialize(StringIO.new(message.serialize.to_s))
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#initialize' do
|
20
|
+
|
21
|
+
it 'adds the global_args to the sections' do
|
22
|
+
expect(message.sections[0]).to eq(type: 0, payload: global_args)
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when flag bits are provided' do
|
26
|
+
|
27
|
+
context 'when valid flags are provided' do
|
28
|
+
|
29
|
+
let(:flags) { [:more_to_come] }
|
30
|
+
|
31
|
+
it 'sets the flags' do
|
32
|
+
expect(message.flags).to eq(flags)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when flags are not provided' do
|
37
|
+
|
38
|
+
let(:flags) { nil }
|
39
|
+
|
40
|
+
it 'sets the flags to [:none]' do
|
41
|
+
expect(message.flags).to eq([:none])
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when an invalid flag is provided' do
|
46
|
+
|
47
|
+
let(:flags) { [:checksum_present, :none] }
|
48
|
+
|
49
|
+
let(:flag_bytes) { message.serialize.to_s[16..19] }
|
50
|
+
|
51
|
+
it 'sets the flags' do
|
52
|
+
expect(message.flags).to eq([:checksum_present, :none])
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'only serializes the valid flags' do
|
56
|
+
expect(flag_bytes).to be_int32(1)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#==' do
|
63
|
+
|
64
|
+
context 'when the other is a msg' do
|
65
|
+
|
66
|
+
context 'when the fields are equal' do
|
67
|
+
|
68
|
+
let(:other) do
|
69
|
+
described_class.new(flags, options, global_args)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'returns true' do
|
73
|
+
expect(message).to eq(other)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when the flags are not equal' do
|
78
|
+
|
79
|
+
let(:other) do
|
80
|
+
described_class.new([:more_to_come], options, global_args)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'returns false' do
|
84
|
+
expect(message).not_to eq(other)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'when the global_args are not equal' do
|
89
|
+
|
90
|
+
let(:other) do
|
91
|
+
described_class.new(flags, nil, { '$db'=> TEST_DB, ismaster: 1 })
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'returns false' do
|
95
|
+
expect(message).not_to eq(other)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when the other is not a msg' do
|
101
|
+
|
102
|
+
let(:other) do
|
103
|
+
expect(message).not_to eq('test')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#hash' do
|
109
|
+
|
110
|
+
let(:values) do
|
111
|
+
message.send(:fields).map do |field|
|
112
|
+
message.instance_variable_get(field[:name])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'returns a hash of the field values' do
|
117
|
+
expect(message.hash).to eq(values.hash)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#replyable?' do
|
122
|
+
|
123
|
+
context 'when the :more_to_come flag is set' do
|
124
|
+
|
125
|
+
let(:flags) { [:more_to_come] }
|
126
|
+
|
127
|
+
it 'returns false' do
|
128
|
+
expect(message).to_not be_replyable
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when the :more_to_come flag is not set' do
|
133
|
+
|
134
|
+
it 'returns true' do
|
135
|
+
expect(message).to be_replyable
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#serialize' do
|
141
|
+
|
142
|
+
let(:bytes) do
|
143
|
+
message.serialize
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:flag_bytes) { bytes.to_s[16..19] }
|
147
|
+
let(:payload_type) { bytes.to_s[20] }
|
148
|
+
let(:payload_bytes) { bytes.to_s[21..-1] }
|
149
|
+
let(:global_args) { { ping: 1 } }
|
150
|
+
|
151
|
+
include_examples 'message with a header'
|
152
|
+
|
153
|
+
context 'when flags are provided' do
|
154
|
+
|
155
|
+
context 'when checksum_present is provided' do
|
156
|
+
|
157
|
+
let(:flags) do
|
158
|
+
[:checksum_present]
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'sets the flag bits' do
|
162
|
+
expect(flag_bytes).to be_int32(1)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context 'when more_to_come is provided' do
|
167
|
+
|
168
|
+
let(:flags) do
|
169
|
+
[:more_to_come]
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'sets the flag bits' do
|
173
|
+
expect(flag_bytes).to be_int32(2)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'when no flag is provided' do
|
179
|
+
|
180
|
+
let(:flags) do
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'sets the flag bits to 0' do
|
185
|
+
expect(flag_bytes).to be_int32(0)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'when global args are provided' do
|
190
|
+
|
191
|
+
it 'sets the payload type' do
|
192
|
+
expect(payload_type).to eq(0.chr)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'serializes the global arguments' do
|
196
|
+
expect(payload_bytes).to be_bson(global_args)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'when additional sections are provided' do
|
201
|
+
|
202
|
+
let(:sections) do
|
203
|
+
[ section ]
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'when an invalid payload type is specified' do
|
207
|
+
|
208
|
+
let(:section) do
|
209
|
+
{ type: 2,
|
210
|
+
payload: { identifier: 'documents',
|
211
|
+
sequence: [ { a: 1 } ] } }
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'raises an exception' do
|
215
|
+
expect {
|
216
|
+
message.serialize
|
217
|
+
}.to raise_exception(Mongo::Error::UnknownPayloadType)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'when a 0 payload type is specified' do
|
222
|
+
|
223
|
+
let(:section) do
|
224
|
+
{ type: 0, payload: { ismaster: 1 } }
|
225
|
+
end
|
226
|
+
|
227
|
+
let(:section_payload_type) { bytes.to_s[36] }
|
228
|
+
let(:section_bytes) { bytes.to_s[37..-1] }
|
229
|
+
|
230
|
+
it 'sets the payload type' do
|
231
|
+
expect(section_payload_type).to eq(0.chr)
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'serializes the section' do
|
235
|
+
expect(section_bytes).to be_bson(section[:payload])
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'when a no payload type is specified' do
|
240
|
+
|
241
|
+
let(:section) do
|
242
|
+
{ payload: { ismaster: 1 } }
|
243
|
+
end
|
244
|
+
|
245
|
+
let(:section_payload_type) { bytes.to_s[36] }
|
246
|
+
let(:section_bytes) { bytes.to_s[37..-1] }
|
247
|
+
|
248
|
+
it 'sets the payload type as 0' do
|
249
|
+
expect(section_payload_type).to eq(0.chr)
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'serializes the section' do
|
253
|
+
expect(section_bytes).to be_bson(section[:payload])
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'when a 1 payload type is specified' do
|
258
|
+
|
259
|
+
let(:section) do
|
260
|
+
{ type: 1,
|
261
|
+
payload: { identifier: 'documents',
|
262
|
+
sequence: [ { a: 1 } ] } }
|
263
|
+
end
|
264
|
+
|
265
|
+
let(:section_payload_type) { bytes.to_s[36] }
|
266
|
+
let(:section_size) { bytes.to_s[37..40] }
|
267
|
+
let(:section_identifier) { bytes.to_s[41..50] }
|
268
|
+
let(:section_bytes) { bytes.to_s[51..-1] }
|
269
|
+
|
270
|
+
it 'sets the payload type' do
|
271
|
+
expect(section_payload_type).to eq(1.chr)
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'sets the section size' do
|
275
|
+
expect(section_size).to be_int32(26)
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'serializes the section identifier' do
|
279
|
+
expect(section_identifier).to eq("documents#{BSON::NULL_BYTE}")
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'serializes the section bytes' do
|
283
|
+
expect(section_bytes).to be_bson({ a: 1 })
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'when two sections are specified' do
|
287
|
+
|
288
|
+
let(:sections) do
|
289
|
+
[ section1, section2 ]
|
290
|
+
end
|
291
|
+
|
292
|
+
let(:section1) do
|
293
|
+
{ type: 1,
|
294
|
+
payload: { identifier: 'documents',
|
295
|
+
sequence: [ { a: 1 } ] } }
|
296
|
+
end
|
297
|
+
|
298
|
+
let(:section2) do
|
299
|
+
{ type: 1,
|
300
|
+
payload: { identifier: 'updates',
|
301
|
+
sequence: [ {:q => { :bar => 1 },
|
302
|
+
:u => { :$set => { :bar => 2 } },
|
303
|
+
:multi => true,
|
304
|
+
:upsert => false } ] } }
|
305
|
+
end
|
306
|
+
|
307
|
+
let(:section1_payload_type) { bytes.to_s[36] }
|
308
|
+
let(:section1_size) { bytes.to_s[37..40] }
|
309
|
+
let(:section1_identifier) { bytes.to_s[41..50] }
|
310
|
+
let(:section1_bytes) { bytes.to_s[51..62] }
|
311
|
+
|
312
|
+
it 'sets the first payload type' do
|
313
|
+
expect(section1_payload_type).to eq(1.chr)
|
314
|
+
end
|
315
|
+
|
316
|
+
it 'sets the first section size' do
|
317
|
+
expect(section1_size).to be_int32(26)
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'serializes the first section identifier' do
|
321
|
+
expect(section1_identifier).to eq("documents#{BSON::NULL_BYTE}")
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'serializes the first section bytes' do
|
325
|
+
expect(section1_bytes).to be_bson({ a: 1 })
|
326
|
+
end
|
327
|
+
|
328
|
+
let(:section2_payload_type) { bytes.to_s[63] }
|
329
|
+
let(:section2_size) { bytes.to_s[64..67] }
|
330
|
+
let(:section2_identifier) { bytes.to_s[68..75] }
|
331
|
+
let(:section2_bytes) { bytes.to_s[76..-1] }
|
332
|
+
|
333
|
+
it 'sets the second payload type' do
|
334
|
+
expect(section2_payload_type).to eq(1.chr)
|
335
|
+
end
|
336
|
+
|
337
|
+
it 'sets the second section size' do
|
338
|
+
expect(section2_size).to be_int32(79)
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'serializes the second section identifier' do
|
342
|
+
expect(section2_identifier).to eq("updates#{BSON::NULL_BYTE}")
|
343
|
+
end
|
344
|
+
|
345
|
+
it 'serializes the second section bytes' do
|
346
|
+
expect(section2_bytes).to be_bson(section2[:payload][:sequence][0])
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context 'when the sections are mixed types and payload type 1 comes before type 0' do
|
352
|
+
|
353
|
+
let(:section1) do
|
354
|
+
{ type: 1,
|
355
|
+
payload: { identifier: 'documents', sequence: [ { 'a' => 1 }]}}
|
356
|
+
end
|
357
|
+
|
358
|
+
let(:section2) do
|
359
|
+
{ type: 0, payload: { 'b' => 2 } }
|
360
|
+
end
|
361
|
+
|
362
|
+
let(:sections) do
|
363
|
+
[ section1, section2 ]
|
364
|
+
end
|
365
|
+
|
366
|
+
it 'serializes all sections' do
|
367
|
+
expect(deserialized.documents).to eq([ BSON::Document.new(global_args), { 'a' => 1 }, { 'b' => 2 }])
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context 'when the validating_keys option is true with payload 1' do
|
373
|
+
|
374
|
+
let(:sections) do
|
375
|
+
[ section ]
|
376
|
+
end
|
377
|
+
|
378
|
+
let(:section) do
|
379
|
+
{ type: 1, payload: { identifier: 'documents', sequence: [ { '$b' => 2 } ] } }
|
380
|
+
end
|
381
|
+
|
382
|
+
let(:options) do
|
383
|
+
{ validating_keys: true }
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'checks the sequence document keys' do
|
387
|
+
expect {
|
388
|
+
message.serialize
|
389
|
+
}.to raise_exception(BSON::String::IllegalKey)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
context 'when the validating_keys option is false with payload 1' do
|
394
|
+
|
395
|
+
let(:sections) do
|
396
|
+
[ section ]
|
397
|
+
end
|
398
|
+
|
399
|
+
let(:section) do
|
400
|
+
{ type: 1, payload: { identifier: 'documents', sequence: [ { '$b' => 2 } ] } }
|
401
|
+
end
|
402
|
+
|
403
|
+
let(:options) do
|
404
|
+
{ validating_keys: false }
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'does not check the sequence document keys' do
|
408
|
+
expect(message.serialize).to be_a(BSON::ByteBuffer)
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
describe '#deserialize' do
|
414
|
+
|
415
|
+
context 'when the payload type is valid' do
|
416
|
+
|
417
|
+
it 'deserializes the message' do
|
418
|
+
expect(deserialized.documents).to eq([ BSON::Document.new(global_args) ])
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
context 'when the payload type is not valid' do
|
423
|
+
|
424
|
+
let(:invalid_payload_message) do
|
425
|
+
message.serialize.to_s.tap do |s|
|
426
|
+
s[20] = 5.chr
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'raises an exception' do
|
431
|
+
expect {
|
432
|
+
Mongo::Protocol::Message.deserialize(StringIO.new(invalid_payload_message))
|
433
|
+
}.to raise_exception(Mongo::Error::UnknownPayloadType)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
describe '#payload' do
|
439
|
+
|
440
|
+
context 'when the msg only contains a payload type 0' do
|
441
|
+
|
442
|
+
it 'creates a payload with the command' do
|
443
|
+
expect(message.payload[:command_name]).to eq(:ping)
|
444
|
+
expect(message.payload[:database_name]).to eq(TEST_DB)
|
445
|
+
expect(message.payload[:command]).to eq('ping' => 1)
|
446
|
+
expect(message.payload[:request_id]).to eq(message.request_id)
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
context 'when the contains a payload type 1' do
|
451
|
+
|
452
|
+
let(:section) do
|
453
|
+
{ type: 1,
|
454
|
+
payload: { identifier: 'documents',
|
455
|
+
sequence: [ { a: 1 } ] } }
|
456
|
+
end
|
457
|
+
|
458
|
+
let(:global_args) do
|
459
|
+
{ '$db' => TEST_DB,
|
460
|
+
'insert' => TEST_COLL,
|
461
|
+
'ordered' => true
|
462
|
+
}
|
463
|
+
end
|
464
|
+
|
465
|
+
let(:sections) do
|
466
|
+
[ section ]
|
467
|
+
end
|
468
|
+
|
469
|
+
let(:expected_command_doc) do
|
470
|
+
{
|
471
|
+
'insert' => TEST_COLL,
|
472
|
+
'documents' => [{ 'a' => 1 }],
|
473
|
+
'ordered' => true
|
474
|
+
}
|
475
|
+
end
|
476
|
+
|
477
|
+
it 'creates a payload with the command' do
|
478
|
+
expect(message.payload[:command_name]).to eq('insert')
|
479
|
+
expect(message.payload[:database_name]).to eq(TEST_DB)
|
480
|
+
expect(message.payload[:command]).to eq(expected_command_doc)
|
481
|
+
expect(message.payload[:request_id]).to eq(message.request_id)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe '#registry' do
|
487
|
+
|
488
|
+
context 'when the class is loaded' do
|
489
|
+
|
490
|
+
it 'registers the op code in the Protocol Registry' do
|
491
|
+
expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'creates an #op_code instance method' do
|
495
|
+
expect(message.op_code).to eq(described_class::OP_CODE)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|