mongo 2.13.0.beta1 → 2.13.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -5
- data/Rakefile +15 -9
- data/lib/mongo.rb +4 -2
- data/lib/mongo/auth/aws/request.rb +4 -2
- data/lib/mongo/bulk_write.rb +1 -0
- data/lib/mongo/client.rb +143 -21
- data/lib/mongo/cluster.rb +53 -17
- data/lib/mongo/cluster/sdam_flow.rb +13 -10
- data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
- data/lib/mongo/cluster/topology/sharded.rb +1 -1
- data/lib/mongo/cluster/topology/single.rb +1 -1
- data/lib/mongo/collection.rb +17 -13
- data/lib/mongo/collection/view/readable.rb +3 -1
- data/lib/mongo/collection/view/writable.rb +41 -5
- data/lib/mongo/database.rb +31 -4
- data/lib/mongo/database/view.rb +19 -4
- data/lib/mongo/distinguishing_semaphore.rb +55 -0
- data/lib/mongo/error.rb +1 -0
- data/lib/mongo/error/invalid_session.rb +2 -1
- data/lib/mongo/error/operation_failure.rb +6 -0
- data/lib/mongo/error/sessions_not_supported.rb +35 -0
- data/lib/mongo/event/base.rb +6 -0
- data/lib/mongo/grid/file.rb +5 -0
- data/lib/mongo/grid/file/chunk.rb +2 -0
- data/lib/mongo/grid/fs_bucket.rb +15 -13
- data/lib/mongo/grid/stream/write.rb +9 -3
- data/lib/mongo/monitoring.rb +38 -0
- data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
- data/lib/mongo/monitoring/event/command_failed.rb +11 -0
- data/lib/mongo/monitoring/event/command_started.rb +37 -2
- data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
- data/lib/mongo/monitoring/event/server_closed.rb +1 -1
- data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
- data/lib/mongo/monitoring/event/server_opening.rb +1 -1
- data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
- data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
- data/lib/mongo/monitoring/publishable.rb +6 -3
- data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
- data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
- data/lib/mongo/protocol/message.rb +36 -8
- data/lib/mongo/protocol/msg.rb +14 -0
- data/lib/mongo/protocol/serializers.rb +5 -2
- data/lib/mongo/server.rb +10 -3
- data/lib/mongo/server/connection.rb +4 -4
- data/lib/mongo/server/connection_base.rb +3 -1
- data/lib/mongo/server/description.rb +5 -0
- data/lib/mongo/server/monitor.rb +76 -44
- data/lib/mongo/server/monitor/connection.rb +55 -7
- data/lib/mongo/server/pending_connection.rb +14 -4
- data/lib/mongo/server/push_monitor.rb +173 -0
- data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
- data/lib/mongo/server_selector.rb +0 -1
- data/lib/mongo/server_selector/base.rb +579 -1
- data/lib/mongo/server_selector/nearest.rb +1 -6
- data/lib/mongo/server_selector/primary.rb +1 -6
- data/lib/mongo/server_selector/primary_preferred.rb +7 -10
- data/lib/mongo/server_selector/secondary.rb +1 -6
- data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
- data/lib/mongo/session.rb +2 -0
- data/lib/mongo/socket.rb +20 -8
- data/lib/mongo/socket/ssl.rb +1 -1
- data/lib/mongo/socket/tcp.rb +1 -1
- data/lib/mongo/topology_version.rb +9 -0
- data/lib/mongo/utils.rb +62 -0
- data/lib/mongo/version.rb +1 -1
- data/spec/README.aws-auth.md +2 -2
- data/spec/integration/awaited_ismaster_spec.rb +28 -0
- data/spec/integration/change_stream_examples_spec.rb +6 -2
- data/spec/integration/check_clean_slate_spec.rb +16 -0
- data/spec/integration/client_construction_spec.rb +1 -0
- data/spec/integration/connect_single_rs_name_spec.rb +5 -2
- data/spec/integration/connection_spec.rb +7 -4
- data/spec/integration/crud_spec.rb +4 -4
- data/spec/integration/docs_examples_spec.rb +6 -0
- data/spec/integration/grid_fs_bucket_spec.rb +48 -0
- data/spec/integration/heartbeat_events_spec.rb +4 -23
- data/spec/integration/read_concern_spec.rb +1 -1
- data/spec/integration/retryable_errors_spec.rb +1 -1
- data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -2
- data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
- data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
- data/spec/integration/sdam_error_handling_spec.rb +37 -15
- data/spec/integration/sdam_events_spec.rb +77 -6
- data/spec/integration/sdam_prose_spec.rb +64 -0
- data/spec/integration/server_monitor_spec.rb +25 -1
- data/spec/integration/size_limit_spec.rb +7 -3
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
- data/spec/integration/ssl_uri_options_spec.rb +2 -2
- data/spec/integration/zlib_compression_spec.rb +25 -0
- data/spec/lite_spec_helper.rb +12 -5
- data/spec/mongo/auth/aws/request_spec.rb +76 -0
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/client_construction_spec.rb +207 -0
- data/spec/mongo/client_spec.rb +38 -3
- data/spec/mongo/cluster/topology/replica_set_spec.rb +52 -9
- data/spec/mongo/cluster/topology/single_spec.rb +4 -2
- data/spec/mongo/cluster_spec.rb +34 -35
- data/spec/mongo/collection/view/change_stream_resume_spec.rb +6 -6
- data/spec/mongo/collection_spec.rb +500 -0
- data/spec/mongo/database_spec.rb +245 -8
- data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
- data/spec/mongo/error/operation_failure_spec.rb +40 -0
- data/spec/mongo/index/view_spec.rb +2 -2
- data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
- data/spec/mongo/protocol/msg_spec.rb +10 -0
- data/spec/mongo/semaphore_spec.rb +51 -0
- data/spec/mongo/server/connection_auth_spec.rb +2 -2
- data/spec/mongo/server_selector/nearest_spec.rb +23 -23
- data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
- data/spec/mongo/server_selector/primary_spec.rb +9 -9
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
- data/spec/mongo/server_selector/secondary_spec.rb +18 -18
- data/spec/mongo/server_selector_spec.rb +4 -4
- data/spec/mongo/session_spec.rb +35 -0
- data/spec/runners/change_streams/test.rb +2 -2
- data/spec/runners/cmap.rb +1 -1
- data/spec/runners/command_monitoring.rb +3 -34
- data/spec/runners/crud/context.rb +9 -5
- data/spec/runners/crud/operation.rb +59 -27
- data/spec/runners/crud/spec.rb +0 -8
- data/spec/runners/crud/test.rb +1 -1
- data/spec/runners/sdam.rb +2 -2
- data/spec/runners/server_selection.rb +242 -28
- data/spec/runners/transactions.rb +12 -12
- data/spec/runners/transactions/operation.rb +151 -25
- data/spec/runners/transactions/test.rb +60 -16
- data/spec/spec_tests/command_monitoring_spec.rb +22 -12
- data/spec/spec_tests/crud_spec.rb +1 -1
- data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -8
- data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
- data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
- data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
- data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
- data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
- data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
- data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
- data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
- data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
- data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
- data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
- data/spec/spec_tests/max_staleness_spec.rb +4 -142
- data/spec/spec_tests/retryable_reads_spec.rb +2 -2
- data/spec/spec_tests/sdam_integration_spec.rb +13 -0
- data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
- data/spec/spec_tests/server_selection_spec.rb +4 -116
- data/spec/stress/cleanup_spec.rb +17 -2
- data/spec/stress/connection_pool_stress_spec.rb +10 -8
- data/spec/support/child_process_helper.rb +78 -0
- data/spec/support/client_registry.rb +1 -0
- data/spec/support/cluster_config.rb +4 -0
- data/spec/support/event_subscriber.rb +123 -33
- data/spec/support/keyword_struct.rb +26 -0
- data/spec/support/shared/server_selector.rb +13 -1
- data/spec/support/spec_config.rb +38 -13
- data/spec/support/spec_organizer.rb +129 -0
- data/spec/support/spec_setup.rb +1 -1
- data/spec/support/utils.rb +46 -0
- metadata +992 -942
- metadata.gz.sig +0 -0
- data/lib/mongo/server_selector/selectable.rb +0 -560
- data/spec/runners/sdam_monitoring.rb +0 -89
@@ -12,7 +12,6 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
require 'runners/transactions/context'
|
16
15
|
require 'runners/transactions/operation'
|
17
16
|
require 'runners/transactions/spec'
|
18
17
|
require 'runners/transactions/test'
|
@@ -26,21 +25,22 @@ def define_transactions_spec_tests(test_paths)
|
|
26
25
|
context(spec.description) do
|
27
26
|
|
28
27
|
define_spec_tests_with_requirements(spec) do |req|
|
28
|
+
|
29
29
|
spec.tests.each do |test|
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
context(test.description) do
|
32
|
+
|
33
|
+
before(:all) do
|
34
|
+
if ClusterConfig.instance.topology == :sharded
|
35
|
+
if test.multiple_mongoses? && SpecConfig.instance.addresses.length == 1
|
36
|
+
skip "Test requires multiple mongoses"
|
37
|
+
elsif !test.multiple_mongoses? && SpecConfig.instance.addresses.length > 1
|
38
|
+
# Many transaction spec tests that do not specifically deal with
|
39
|
+
# sharded transactions fail when run against a multi-mongos cluster
|
40
|
+
skip "Test does not specify multiple mongoses"
|
41
|
+
end
|
39
42
|
end
|
40
43
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context(test.description) do
|
44
44
|
|
45
45
|
if test.skip_reason
|
46
46
|
before(:all) do
|
@@ -21,23 +21,8 @@ module Mongo
|
|
21
21
|
arguments && arguments['session'] || object =~ /session/
|
22
22
|
end
|
23
23
|
|
24
|
-
def execute(target,
|
25
|
-
|
26
|
-
when 'session0'
|
27
|
-
session0
|
28
|
-
when 'session1'
|
29
|
-
session1
|
30
|
-
else
|
31
|
-
# active session could be nil
|
32
|
-
active_session
|
33
|
-
end
|
34
|
-
|
35
|
-
context = Context.new(
|
36
|
-
session0,
|
37
|
-
session1,
|
38
|
-
session)
|
39
|
-
|
40
|
-
op_name = Utils.underscore(name).to_sym
|
24
|
+
def execute(target, context)
|
25
|
+
op_name = ::Utils.underscore(name).to_sym
|
41
26
|
if op_name == :with_transaction
|
42
27
|
args = [target]
|
43
28
|
else
|
@@ -53,9 +38,14 @@ module Mongo
|
|
53
38
|
result['error'] = false
|
54
39
|
end
|
55
40
|
end
|
41
|
+
|
56
42
|
result
|
57
43
|
rescue Mongo::Error::OperationFailure => e
|
58
|
-
|
44
|
+
result = e.instance_variable_get(:@result)
|
45
|
+
if result.nil?
|
46
|
+
raise "OperationFailure had nil result: #{e}"
|
47
|
+
end
|
48
|
+
err_doc = result.send(:first_document)
|
59
49
|
error_code_name = err_doc['codeName'] || err_doc['writeConcernError'] && err_doc['writeConcernError']['codeName']
|
60
50
|
if error_code_name.nil?
|
61
51
|
# Sometimes the server does not return the error code name,
|
@@ -102,13 +92,13 @@ module Mongo
|
|
102
92
|
command_value = cmd.delete(command_name)
|
103
93
|
cmd = { command_name.to_sym => command_value }.merge(cmd)
|
104
94
|
|
105
|
-
opts = Utils.snakeize_hash(context
|
95
|
+
opts = ::Utils.snakeize_hash(transformed_options(context)).dup
|
106
96
|
opts[:read] = opts.delete(:read_preference)
|
107
97
|
database.command(cmd, opts).documents.first
|
108
98
|
end
|
109
99
|
|
110
100
|
def start_transaction(session, context)
|
111
|
-
session.start_transaction(Utils.convert_operation_options(arguments['options']))
|
101
|
+
session.start_transaction(::Utils.convert_operation_options(arguments['options']))
|
112
102
|
nil
|
113
103
|
end
|
114
104
|
|
@@ -128,7 +118,7 @@ module Mongo
|
|
128
118
|
end
|
129
119
|
|
130
120
|
if arguments['options']
|
131
|
-
options = Utils.snakeize_hash(arguments['options'])
|
121
|
+
options = ::Utils.snakeize_hash(arguments['options'])
|
132
122
|
else
|
133
123
|
options = nil
|
134
124
|
end
|
@@ -136,7 +126,7 @@ module Mongo
|
|
136
126
|
callback['operations'].each do |op_spec|
|
137
127
|
op = Operation.new(@crud_test, op_spec)
|
138
128
|
target = @crud_test.resolve_target(@crud_test.test_client, op)
|
139
|
-
rv = op.execute(target, context
|
129
|
+
rv = op.execute(target, context)
|
140
130
|
if rv && rv['exception']
|
141
131
|
raise rv['exception']
|
142
132
|
end
|
@@ -151,7 +141,7 @@ module Mongo
|
|
151
141
|
end
|
152
142
|
|
153
143
|
def targeted_fail_point(collection, context)
|
154
|
-
args = context
|
144
|
+
args = transformed_options(context)
|
155
145
|
session = args[:session]
|
156
146
|
unless session.pinned_server
|
157
147
|
raise ArgumentError, 'Targeted fail point requires session to be pinned to a server'
|
@@ -169,7 +159,7 @@ module Mongo
|
|
169
159
|
end
|
170
160
|
|
171
161
|
def assert_session_pinned(collection, context)
|
172
|
-
args = context
|
162
|
+
args = transformed_options(context)
|
173
163
|
session = args[:session]
|
174
164
|
unless session.pinned_server
|
175
165
|
raise ArgumentError, 'Expected session to be pinned'
|
@@ -177,12 +167,148 @@ module Mongo
|
|
177
167
|
end
|
178
168
|
|
179
169
|
def assert_session_unpinned(collection, context)
|
180
|
-
args = context
|
170
|
+
args = transformed_options(context)
|
181
171
|
session = args[:session]
|
182
172
|
if session.pinned_server
|
183
173
|
raise ArgumentError, 'Expected session to not be pinned'
|
184
174
|
end
|
185
175
|
end
|
176
|
+
|
177
|
+
def wait_for_event(client, context)
|
178
|
+
deadline = Time.now + 5
|
179
|
+
loop do
|
180
|
+
events = _select_events(context)
|
181
|
+
if events.length >= arguments['count']
|
182
|
+
break
|
183
|
+
end
|
184
|
+
if Time.now >= deadline
|
185
|
+
raise "Did not receive an event matching #{arguments} in 5 seconds; received #{events.length} but expected #{arguments['count']} events"
|
186
|
+
else
|
187
|
+
sleep 0.1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def assert_event_count(client, context)
|
193
|
+
events = _select_events(context)
|
194
|
+
unless events.length == arguments['count']
|
195
|
+
raise "Exppected #{arguments['count']} #{arguments['event']} events, but have #{events.length}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def _select_events(context)
|
200
|
+
case arguments['event']
|
201
|
+
when 'ServerMarkedUnknownEvent'
|
202
|
+
context.sdam_subscriber.all_events.select do |event|
|
203
|
+
event.is_a?(Mongo::Monitoring::Event::ServerDescriptionChanged) &&
|
204
|
+
event.new_description.unknown?
|
205
|
+
end
|
206
|
+
else
|
207
|
+
context.sdam_subscriber.all_events.select do |event|
|
208
|
+
event.class.name.sub(/.*::/, '') == arguments['event'].sub(/Event$/, '')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class ThreadContext
|
214
|
+
def initialize
|
215
|
+
@operations = Queue.new
|
216
|
+
@unexpected_operation_results = []
|
217
|
+
end
|
218
|
+
|
219
|
+
def stop?
|
220
|
+
!!@stop
|
221
|
+
end
|
222
|
+
|
223
|
+
def signal_stop
|
224
|
+
@stop = true
|
225
|
+
end
|
226
|
+
|
227
|
+
attr_reader :operations
|
228
|
+
attr_reader :unexpected_operation_results
|
229
|
+
end
|
230
|
+
|
231
|
+
def start_thread(client, context)
|
232
|
+
thread_context = ThreadContext.new
|
233
|
+
thread = Thread.new do
|
234
|
+
loop do
|
235
|
+
begin
|
236
|
+
op_spec = thread_context.operations.pop(true)
|
237
|
+
op = Operation.new(@crud_test, op_spec)
|
238
|
+
target = @crud_test.resolve_target(@crud_test.test_client, op)
|
239
|
+
result = op.execute(target, context)
|
240
|
+
if op_spec['error']
|
241
|
+
unless result['error']
|
242
|
+
thread_context.unexpected_operation_results << result
|
243
|
+
end
|
244
|
+
else
|
245
|
+
if result['error']
|
246
|
+
thread_context.unexpected_operation_results << result
|
247
|
+
end
|
248
|
+
end
|
249
|
+
rescue ThreadError
|
250
|
+
# Queue is empty
|
251
|
+
end
|
252
|
+
if thread_context.stop?
|
253
|
+
break
|
254
|
+
else
|
255
|
+
sleep 1
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
class << thread
|
260
|
+
attr_accessor :context
|
261
|
+
end
|
262
|
+
thread.context = thread_context
|
263
|
+
unless context.threads
|
264
|
+
context.threads ||= {}
|
265
|
+
end
|
266
|
+
context.threads[arguments['name']] = thread
|
267
|
+
end
|
268
|
+
|
269
|
+
def run_on_thread(client, context)
|
270
|
+
thread = context.threads.fetch(arguments['name'])
|
271
|
+
thread.context.operations << arguments['operation']
|
272
|
+
end
|
273
|
+
|
274
|
+
def wait_for_thread(client, context)
|
275
|
+
thread = context.threads.fetch(arguments['name'])
|
276
|
+
thread.context.signal_stop
|
277
|
+
thread.join
|
278
|
+
unless thread.context.unexpected_operation_results.empty?
|
279
|
+
raise "Thread #{arguments['name']} had #{thread.context.unexpected_operation_results}.length unexpected operation results"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def wait(client, context)
|
284
|
+
sleep arguments['ms'] / 1000.0
|
285
|
+
end
|
286
|
+
|
287
|
+
def record_primary(client, context)
|
288
|
+
context.primary_address = client.cluster.next_primary.address
|
289
|
+
end
|
290
|
+
|
291
|
+
def run_admin_command(support_client, context)
|
292
|
+
support_client.use('admin').database.command(arguments['command'])
|
293
|
+
end
|
294
|
+
|
295
|
+
def wait_for_primary_change(client, context)
|
296
|
+
timeout = if arguments['timeoutMS']
|
297
|
+
arguments['timeoutMS'] / 1000.0
|
298
|
+
else
|
299
|
+
10
|
300
|
+
end
|
301
|
+
deadline = Time.now + timeout
|
302
|
+
loop do
|
303
|
+
client.cluster.scan!
|
304
|
+
if client.cluster.next_primary.address != context.primary_address
|
305
|
+
break
|
306
|
+
end
|
307
|
+
if Time.now >= deadline
|
308
|
+
raise "Failed to change primary in #{timeout} seconds"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
186
312
|
end
|
187
313
|
end
|
188
314
|
end
|
@@ -41,13 +41,20 @@ module Mongo
|
|
41
41
|
@spec = crud_spec
|
42
42
|
@data = data
|
43
43
|
@description = test['description']
|
44
|
-
@client_options =
|
44
|
+
@client_options = {
|
45
|
+
# Disable legacy read & write retries, so that when spec tests
|
46
|
+
# disable modern retries we do not retry at all instead of using
|
47
|
+
# legacy retries which is contrary to what the tests want.
|
48
|
+
max_read_retries: 0,
|
49
|
+
max_write_retries: 0,
|
50
|
+
app_name: 'Tx spec - test client',
|
51
|
+
}.update(::Utils.convert_client_options(test['clientOptions'] || {}))
|
45
52
|
|
46
53
|
@fail_point_command = test['failPoint']
|
47
54
|
|
48
55
|
@session_options = if opts = test['sessionOptions']
|
49
56
|
Hash[opts.map do |session_name, options|
|
50
|
-
[session_name.to_sym, Utils.convert_operation_options(options)]
|
57
|
+
[session_name.to_sym, ::Utils.convert_operation_options(options)]
|
51
58
|
end]
|
52
59
|
else
|
53
60
|
{}
|
@@ -107,15 +114,35 @@ module Mongo
|
|
107
114
|
end
|
108
115
|
|
109
116
|
def test_client
|
110
|
-
@test_client ||=
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
117
|
+
@test_client ||= begin
|
118
|
+
sdam_proc = lambda do |test_client|
|
119
|
+
test_client.subscribe(Mongo::Monitoring::COMMAND, command_subscriber)
|
120
|
+
|
121
|
+
test_client.subscribe(Mongo::Monitoring::TOPOLOGY_OPENING, sdam_subscriber)
|
122
|
+
test_client.subscribe(Mongo::Monitoring::SERVER_OPENING, sdam_subscriber)
|
123
|
+
test_client.subscribe(Mongo::Monitoring::SERVER_DESCRIPTION_CHANGED, sdam_subscriber)
|
124
|
+
test_client.subscribe(Mongo::Monitoring::TOPOLOGY_CHANGED, sdam_subscriber)
|
125
|
+
test_client.subscribe(Mongo::Monitoring::SERVER_CLOSED, sdam_subscriber)
|
126
|
+
test_client.subscribe(Mongo::Monitoring::TOPOLOGY_CLOSED, sdam_subscriber)
|
127
|
+
test_client.subscribe(Mongo::Monitoring::CONNECTION_POOL, sdam_subscriber)
|
128
|
+
end
|
129
|
+
|
130
|
+
ClientRegistry.instance.new_local_client(
|
131
|
+
SpecConfig.instance.addresses,
|
132
|
+
SpecConfig.instance.authorized_test_options.merge(
|
133
|
+
database: @spec.database_name,
|
134
|
+
auth_source: SpecConfig.instance.auth_options[:auth_source] || 'admin',
|
135
|
+
sdam_proc: sdam_proc,
|
136
|
+
).merge(@client_options))
|
137
|
+
end
|
115
138
|
end
|
116
139
|
|
117
|
-
def
|
118
|
-
@
|
140
|
+
def command_subscriber
|
141
|
+
@command_subscriber ||= EventSubscriber.new
|
142
|
+
end
|
143
|
+
|
144
|
+
def sdam_subscriber
|
145
|
+
@sdam_subscriber ||= EventSubscriber.new(name: 'sdam subscriber')
|
119
146
|
end
|
120
147
|
|
121
148
|
# Run the test.
|
@@ -127,17 +154,33 @@ module Mongo
|
|
127
154
|
#
|
128
155
|
# @since 2.6.0
|
129
156
|
def run
|
130
|
-
|
157
|
+
@threads = {}
|
131
158
|
|
132
159
|
results = @operations.map do |op|
|
133
160
|
target = resolve_target(test_client, op)
|
134
161
|
if op.needs_session?
|
135
|
-
|
162
|
+
context = CRUD::Context.new(
|
163
|
+
session0: session0,
|
164
|
+
session1: session1,
|
165
|
+
sdam_subscriber: sdam_subscriber,
|
166
|
+
threads: @threads,
|
167
|
+
primary_address: @primary_address,
|
168
|
+
)
|
136
169
|
else
|
137
170
|
# Hack to support write concern operations tests, which are
|
138
171
|
# defined to use transactions format but target pre-3.6 servers
|
139
172
|
# that do not support sessions
|
140
|
-
|
173
|
+
target ||= support_client
|
174
|
+
context = CRUD::Context.new(
|
175
|
+
sdam_subscriber: sdam_subscriber,
|
176
|
+
threads: @threads,
|
177
|
+
primary_address: @primary_address,
|
178
|
+
)
|
179
|
+
end
|
180
|
+
|
181
|
+
op.execute(target, context).tap do
|
182
|
+
@threads = context.threads
|
183
|
+
@primary_address = context.primary_address
|
141
184
|
end
|
142
185
|
end
|
143
186
|
|
@@ -147,7 +190,7 @@ module Mongo
|
|
147
190
|
@session0&.end_session
|
148
191
|
@session1&.end_session
|
149
192
|
|
150
|
-
actual_events = Utils.yamlify_command_events(
|
193
|
+
actual_events = ::Utils.yamlify_command_events(command_subscriber.started_events)
|
151
194
|
actual_events = actual_events.reject do |event|
|
152
195
|
event['command_started_event']['command']['endSessions']
|
153
196
|
end
|
@@ -169,7 +212,7 @@ module Mongo
|
|
169
212
|
contents: @result_collection.with(
|
170
213
|
read: {mode: 'primary'},
|
171
214
|
read_concern: { level: 'local' },
|
172
|
-
).find.to_a,
|
215
|
+
).find.sort(_id: 1).to_a,
|
173
216
|
events: actual_events,
|
174
217
|
}
|
175
218
|
end
|
@@ -216,9 +259,10 @@ module Mongo
|
|
216
259
|
|
217
260
|
coll.insert_many(@data) unless @data.empty?
|
218
261
|
|
219
|
-
$distinct_ran ||=
|
262
|
+
$distinct_ran ||= {}
|
263
|
+
$distinct_ran[@spec.database_name] ||= if description =~ /distinct/ || @operations.any? { |op| op.name == 'distinct' }
|
220
264
|
mongos_each_direct_client do |direct_client|
|
221
|
-
direct_client['test'].distinct('foo').to_a
|
265
|
+
direct_client.use(@spec.database_name)['test'].distinct('foo').to_a
|
222
266
|
end
|
223
267
|
end
|
224
268
|
|
@@ -20,7 +20,7 @@ describe 'Command Monitoring Events' do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
let(:subscriber) do
|
23
|
-
|
23
|
+
EventSubscriber.new
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:monitoring) do
|
@@ -32,25 +32,35 @@ describe 'Command Monitoring Events' do
|
|
32
32
|
authorized_client.subscribe(Mongo::Monitoring::COMMAND, subscriber)
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
monitoring.subscribers[Mongo::Monitoring::COMMAND].delete(subscriber)
|
37
|
-
authorized_collection.find.delete_many
|
38
|
-
end
|
39
|
-
|
40
|
-
test.expectations.each do |expectation|
|
35
|
+
test.expectations.each_with_index do |expectation, index|
|
41
36
|
|
42
37
|
it "generates a #{expectation.event_name} for #{expectation.command_name}" do
|
43
38
|
begin
|
44
|
-
test.run(authorized_collection)
|
45
|
-
|
46
|
-
expect(event).to send(expectation.matcher, expectation)
|
39
|
+
test.run(authorized_collection, subscriber)
|
40
|
+
check_event(subscriber, index, expectation)
|
47
41
|
rescue Mongo::Error::OperationFailure, Mongo::Error::BulkWriteError
|
48
|
-
|
49
|
-
expect(event).to send(expectation.matcher, expectation)
|
42
|
+
check_event(subscriber, index, expectation)
|
50
43
|
end
|
51
44
|
end
|
52
45
|
end
|
53
46
|
end
|
54
47
|
end
|
55
48
|
end
|
49
|
+
|
50
|
+
def check_event(subscriber, index, expectation)
|
51
|
+
subscriber.all_events.length.should > index
|
52
|
+
# TODO move this filtering into EventSubscriber
|
53
|
+
events = subscriber.all_events.reject do |event|
|
54
|
+
(
|
55
|
+
event.is_a?(Mongo::Monitoring::Event::CommandStarted) ||
|
56
|
+
event.is_a?(Mongo::Monitoring::Event::CommandSucceeded) ||
|
57
|
+
event.is_a?(Mongo::Monitoring::Event::CommandFailed)
|
58
|
+
) &&
|
59
|
+
%w(authenticate getnonce saslStart saslContinue).include?(event.command_name)
|
60
|
+
end
|
61
|
+
actual_event = events[index]
|
62
|
+
expected_event_type = expectation.event_type.sub(/_event$/, '')
|
63
|
+
Utils.underscore(actual_event.class.name.sub(/.*::/, '')).to_s.should == expected_event_type
|
64
|
+
expect(actual_event).to send(expectation.matcher, expectation)
|
65
|
+
end
|
56
66
|
end
|