mongo 2.10.5 → 2.11.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.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +2 -0
  6. data/lib/mongo/address.rb +4 -0
  7. data/lib/mongo/address/validator.rb +99 -0
  8. data/lib/mongo/auth.rb +7 -2
  9. data/lib/mongo/auth/user.rb +1 -7
  10. data/lib/mongo/background_thread.rb +135 -0
  11. data/lib/mongo/bulk_write/transformable.rb +3 -3
  12. data/lib/mongo/client.rb +74 -16
  13. data/lib/mongo/cluster.rb +193 -41
  14. data/lib/mongo/cluster/periodic_executor.rb +31 -43
  15. data/lib/mongo/cluster/sdam_flow.rb +26 -3
  16. data/lib/mongo/cluster/srv_monitor.rb +127 -0
  17. data/lib/mongo/collection/view/readable.rb +3 -5
  18. data/lib/mongo/collection/view/writable.rb +3 -3
  19. data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
  20. data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
  21. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  22. data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
  23. data/lib/mongo/error.rb +1 -0
  24. data/lib/mongo/error/auth_error.rb +1 -1
  25. data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
  26. data/lib/mongo/error/invalid_address.rb +24 -0
  27. data/lib/mongo/error/notable.rb +2 -2
  28. data/lib/mongo/error/operation_failure.rb +3 -3
  29. data/lib/mongo/error/pool_closed_error.rb +11 -4
  30. data/lib/mongo/event.rb +1 -1
  31. data/lib/mongo/grid/file.rb +0 -5
  32. data/lib/mongo/grid/file/chunk.rb +0 -2
  33. data/lib/mongo/grid/fs_bucket.rb +13 -15
  34. data/lib/mongo/grid/stream/write.rb +3 -9
  35. data/lib/mongo/loggable.rb +5 -1
  36. data/lib/mongo/monitoring.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
  38. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
  39. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
  40. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
  41. data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
  42. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
  43. data/lib/mongo/operation/shared/executable.rb +5 -10
  44. data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
  45. data/lib/mongo/protocol/get_more.rb +1 -2
  46. data/lib/mongo/protocol/kill_cursors.rb +13 -6
  47. data/lib/mongo/protocol/serializers.rb +4 -20
  48. data/lib/mongo/retryable.rb +9 -34
  49. data/lib/mongo/semaphore.rb +1 -1
  50. data/lib/mongo/server.rb +113 -42
  51. data/lib/mongo/server/connection.rb +12 -5
  52. data/lib/mongo/server/connection_pool.rb +250 -40
  53. data/lib/mongo/server/connection_pool/populator.rb +58 -0
  54. data/lib/mongo/server/description.rb +9 -2
  55. data/lib/mongo/server/monitor.rb +68 -93
  56. data/lib/mongo/server/monitor/connection.rb +2 -0
  57. data/lib/mongo/server_selector/selectable.rb +13 -5
  58. data/lib/mongo/session.rb +0 -13
  59. data/lib/mongo/srv.rb +17 -0
  60. data/lib/mongo/srv/monitor.rb +96 -0
  61. data/lib/mongo/srv/resolver.rb +130 -0
  62. data/lib/mongo/srv/result.rb +126 -0
  63. data/lib/mongo/srv/warning_result.rb +35 -0
  64. data/lib/mongo/uri.rb +45 -55
  65. data/lib/mongo/uri/srv_protocol.rb +89 -42
  66. data/lib/mongo/version.rb +1 -1
  67. data/mongo.gemspec +3 -4
  68. data/spec/README.md +6 -1
  69. data/spec/enterprise_auth/kerberos_spec.rb +7 -6
  70. data/spec/integration/change_stream_examples_spec.rb +0 -4
  71. data/spec/integration/client_construction_spec.rb +14 -2
  72. data/spec/integration/connect_single_rs_name_spec.rb +2 -2
  73. data/spec/integration/connection_pool_populator_spec.rb +296 -0
  74. data/spec/integration/connection_spec.rb +31 -22
  75. data/spec/integration/cursor_reaping_spec.rb +1 -2
  76. data/spec/integration/docs_examples_spec.rb +0 -4
  77. data/spec/integration/heartbeat_events_spec.rb +17 -15
  78. data/spec/integration/reconnect_spec.rb +144 -1
  79. data/spec/integration/retryable_writes_errors_spec.rb +0 -4
  80. data/spec/integration/retryable_writes_spec.rb +36 -36
  81. data/spec/integration/sdam_error_handling_spec.rb +31 -25
  82. data/spec/integration/sdam_events_spec.rb +2 -6
  83. data/spec/integration/server_monitor_spec.rb +28 -0
  84. data/spec/integration/server_selector_spec.rb +7 -5
  85. data/spec/integration/srv_monitoring_spec.rb +360 -0
  86. data/spec/integration/step_down_spec.rb +4 -6
  87. data/spec/lite_spec_helper.rb +22 -0
  88. data/spec/mongo/address/validator_spec.rb +51 -0
  89. data/spec/mongo/auth/cr_spec.rb +1 -29
  90. data/spec/mongo/auth/ldap_spec.rb +1 -29
  91. data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
  92. data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
  93. data/spec/mongo/auth/scram_spec.rb +1 -29
  94. data/spec/mongo/auth/user/view_spec.rb +1 -36
  95. data/spec/mongo/auth/user_spec.rb +0 -12
  96. data/spec/mongo/auth/x509_spec.rb +1 -29
  97. data/spec/mongo/bulk_write_spec.rb +2 -2
  98. data/spec/mongo/client_construction_spec.rb +56 -15
  99. data/spec/mongo/client_spec.rb +31 -27
  100. data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
  101. data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
  102. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
  103. data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
  104. data/spec/mongo/cluster/topology/single_spec.rb +20 -11
  105. data/spec/mongo/cluster_spec.rb +45 -29
  106. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
  107. data/spec/mongo/collection/view/readable_spec.rb +0 -16
  108. data/spec/mongo/collection_spec.rb +0 -44
  109. data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
  110. data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
  111. data/spec/mongo/cursor_spec.rb +27 -7
  112. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
  113. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
  114. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
  115. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
  116. data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
  117. data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
  118. data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
  119. data/spec/mongo/retryable_spec.rb +52 -31
  120. data/spec/mongo/server/app_metadata_spec.rb +0 -8
  121. data/spec/mongo/server/connection_auth_spec.rb +5 -2
  122. data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
  123. data/spec/mongo/server/connection_pool_spec.rb +256 -107
  124. data/spec/mongo/server/connection_spec.rb +22 -33
  125. data/spec/mongo/server/description_spec.rb +42 -4
  126. data/spec/mongo/server/monitor/connection_spec.rb +22 -11
  127. data/spec/mongo/server/monitor_spec.rb +66 -107
  128. data/spec/mongo/server_spec.rb +82 -60
  129. data/spec/mongo/session/session_pool_spec.rb +1 -5
  130. data/spec/mongo/session_spec.rb +0 -4
  131. data/spec/mongo/socket/ssl_spec.rb +2 -2
  132. data/spec/mongo/srv/monitor_spec.rb +211 -0
  133. data/spec/mongo/srv/result_spec.rb +54 -0
  134. data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
  135. data/spec/mongo/uri_spec.rb +125 -4
  136. data/spec/spec_helper.rb +6 -0
  137. data/spec/spec_tests/auth_spec.rb +39 -0
  138. data/spec/spec_tests/cmap_spec.rb +55 -8
  139. data/spec/spec_tests/connection_string_spec.rb +6 -31
  140. data/spec/spec_tests/data/auth/connection-string.yml +297 -0
  141. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
  142. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
  143. data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
  144. data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
  145. data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
  146. data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
  147. data/spec/spec_tests/data/transactions/abort.yml +3 -3
  148. data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
  149. data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
  150. data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
  151. data/spec/spec_tests/max_staleness_spec.rb +7 -2
  152. data/spec/spec_tests/retryable_reads_spec.rb +0 -31
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
  154. data/spec/spec_tests/sdam_spec.rb +4 -7
  155. data/spec/spec_tests/server_selection_spec.rb +6 -2
  156. data/spec/spec_tests/transactions_spec.rb +0 -2
  157. data/spec/spec_tests/uri_options_spec.rb +4 -2
  158. data/spec/stress/connection_pool_stress_spec.rb +203 -0
  159. data/spec/stress/connection_pool_timing_spec.rb +181 -0
  160. data/spec/support/auth.rb +113 -0
  161. data/spec/support/background_thread_registry.rb +63 -0
  162. data/spec/support/client_registry.rb +11 -2
  163. data/spec/support/cluster_config.rb +65 -46
  164. data/spec/support/cluster_tools.rb +2 -2
  165. data/spec/support/cmap.rb +13 -14
  166. data/spec/support/cmap/verifier.rb +4 -5
  167. data/spec/support/command_monitoring.rb +0 -5
  168. data/spec/support/common_shortcuts.rb +101 -1
  169. data/spec/support/constraints.rb +25 -0
  170. data/spec/support/dns.rb +13 -0
  171. data/spec/support/event_subscriber.rb +0 -7
  172. data/spec/support/json_ext_formatter.rb +5 -1
  173. data/spec/support/lite_constraints.rb +22 -6
  174. data/spec/support/local_resource_registry.rb +34 -0
  175. data/spec/support/sdam_monitoring.rb +115 -0
  176. data/spec/support/spec_config.rb +20 -6
  177. data/spec/support/spec_setup.rb +2 -2
  178. data/spec/support/transactions.rb +1 -1
  179. data/spec/support/transactions/test.rb +1 -1
  180. data/spec/support/utils.rb +1 -16
  181. metadata +685 -659
  182. metadata.gz.sig +0 -0
  183. data/lib/mongo/event/description_changed.rb +0 -52
  184. data/spec/integration/bson_symbol_spec.rb +0 -34
  185. data/spec/integration/crud_spec.rb +0 -45
  186. data/spec/integration/get_more_spec.rb +0 -32
  187. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  188. data/spec/integration/retryable_errors_spec.rb +0 -265
  189. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
  190. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  191. data/spec/runners/sdam/verifier.rb +0 -88
@@ -349,6 +349,8 @@ class ClusterTools
349
349
  end
350
350
  end
351
351
 
352
+ private
353
+
352
354
  def each_server(&block)
353
355
  admin_client.cluster.servers_list.each(&block)
354
356
  end
@@ -359,8 +361,6 @@ class ClusterTools
359
361
  end
360
362
  end
361
363
 
362
- private
363
-
364
364
  def reset_server_states
365
365
  each_server do |server|
366
366
  server.unknown!
data/spec/support/cmap.rb CHANGED
@@ -53,21 +53,17 @@ module Mongo
53
53
  preprocess
54
54
  end
55
55
 
56
- def setup(cluster)
57
- @subscriber = EventSubscriber.new
58
-
59
- monitoring = Mongo::Monitoring.new(monitoring: false)
60
- monitoring.subscribe(Mongo::Monitoring::CONNECTION_POOL, subscriber)
61
-
62
- server = Mongo::Server.new(
63
- Address.new(SpecConfig.instance.addresses.first),
64
- cluster,
65
- monitoring,
66
- Mongo::Event::Listeners.new,
67
- pool_options.merge(monitoring_io: false))
68
-
56
+ def setup(server, subscriber)
57
+ @subscriber = subscriber
69
58
  @pool = server.pool
70
- @pool.populate
59
+
60
+ # let pool populate
61
+ ([0.1, 0.15, 0.15] + [0.2] * 20).each do |t|
62
+ if @pool.size >= @pool.min_size
63
+ break
64
+ end
65
+ sleep t
66
+ end
71
67
  end
72
68
 
73
69
  def run
@@ -170,6 +166,9 @@ module Mongo
170
166
  end
171
167
 
172
168
  # Converts the options given by the spec to the Ruby driver format.
169
+ #
170
+ # This method only handles options used by spec tests at the time when
171
+ # this method was written. Other options are silently dropped.
173
172
  def process_options(options)
174
173
  (options || {}).reduce({}) do |opts, kv|
175
174
  case kv.first
@@ -27,14 +27,13 @@ module Mongo
27
27
  expect(expected).to be_a(Hash)
28
28
  expect(actual).to be_a(Hash)
29
29
 
30
- actual = actual.dup
30
+ actual_modified = actual.dup
31
31
  if actual['reason']
32
- actual['reason'] = actual['reason'].to_s.gsub(/_[a-z]/) { |m| m[1].upcase }
32
+ actual_modified['reason'] = actual['reason'].to_s.gsub(/_[a-z]/) { |m| m[1].upcase }
33
33
  end
34
34
 
35
- actual_modified = actual.dup
36
- actual_modified.each do |k, v|
37
- if expected.key?(k) && expected[k] == 42
35
+ actual.each do |k, v|
36
+ if expected.key?(k) && expected[k] == 42 && v
38
37
  actual_modified[k] = 42
39
38
  end
40
39
  end
@@ -134,11 +134,6 @@ module Mongo
134
134
  end
135
135
  if expected.keys.first == '$numberLong'
136
136
  converted = expected.values.first.to_i
137
- if actual.is_a?(BSON::Int64)
138
- actual = Utils.int64_value(actual)
139
- elsif actual.is_a?(BSON::Int32)
140
- return false
141
- end
142
137
  (actual == converted) || actual >= 0
143
138
  else
144
139
  expected.each do |key, value|
@@ -16,6 +16,7 @@ module CommonShortcuts
16
16
  def clean_slate
17
17
  before do
18
18
  ClientRegistry.instance.close_all_clients
19
+ BackgroundThreadRegistry.instance.verify_empty!
19
20
  end
20
21
  end
21
22
 
@@ -25,6 +26,7 @@ module CommonShortcuts
25
26
  def clean_slate_for_all
26
27
  before(:all) do
27
28
  ClientRegistry.instance.close_all_clients
29
+ BackgroundThreadRegistry.instance.verify_empty!
28
30
  end
29
31
  end
30
32
 
@@ -107,7 +109,13 @@ module CommonShortcuts
107
109
  allow(cluster).to receive(:topology).and_return(topology)
108
110
  allow(cluster).to receive(:app_metadata)
109
111
  allow(cluster).to receive(:options).and_return({})
110
- server = Mongo::Server.new(address, cluster, monitoring, listeners, SpecConfig.instance.test_options)
112
+ allow(cluster).to receive(:run_sdam_flow)
113
+ allow(cluster).to receive(:heartbeat_interval).and_return(10)
114
+ server = Mongo::Server.new(address, cluster, monitoring, listeners,
115
+ SpecConfig.instance.test_options.merge(monitoring_io: false))
116
+ # Since the server references a double for the cluster, the server
117
+ # must be closed in the scope of the example.
118
+ register_server(server)
111
119
  description = Mongo::Server::Description.new(address, ismaster, average_round_trip_time)
112
120
  server.tap do |s|
113
121
  allow(s).to receive(:description).and_return(description)
@@ -138,5 +146,97 @@ module CommonShortcuts
138
146
  'ok' => 0, 'code' => 91, 'errmsg' => 'shutdown in progress'
139
147
  )
140
148
  end
149
+
150
+ def register_cluster(cluster)
151
+ finalizer = lambda do |cluster|
152
+ cluster.disconnect!
153
+ end
154
+ LocalResourceRegistry.instance.register(cluster, finalizer)
155
+ end
156
+
157
+ def register_server(server)
158
+ finalizer = lambda do |server|
159
+ if server.connected?
160
+ server.disconnect!
161
+ end
162
+ end
163
+ LocalResourceRegistry.instance.register(server, finalizer)
164
+ end
165
+
166
+ def register_background_thread_object(bgt_object)
167
+ finalizer = lambda do |bgt_object|
168
+ bgt_object.stop!
169
+ end
170
+ LocalResourceRegistry.instance.register(bgt_object, finalizer)
171
+ end
172
+
173
+ def register_pool(pool)
174
+ finalizer = lambda do |pool|
175
+ if !pool.closed?
176
+ pool.close(wait: true)
177
+ end
178
+ end
179
+ LocalResourceRegistry.instance.register(pool, finalizer)
180
+ end
181
+
182
+ # Stop monitoring threads on the specified clients, after ensuring
183
+ # each client has a writable server. Used for tests which assert on
184
+ # global side effects like log messages being generated, to prevent
185
+ # background threads from interfering with assertions.
186
+ def stop_monitoring(*clients)
187
+ clients.each do |client|
188
+ client.cluster.next_primary
189
+ client.cluster.disconnect!
190
+ end
191
+ end
192
+
193
+ DNS_INTERFACES = [
194
+ [:udp, "0.0.0.0", 5300],
195
+ [:tcp, "0.0.0.0", 5300],
196
+ ]
197
+
198
+ def mock_dns(config)
199
+ semaphore = Mongo::Semaphore.new
200
+
201
+ thread = Thread.new do
202
+ RubyDNS::run_server(DNS_INTERFACES) do
203
+ config.each do |(query, type, *answers)|
204
+
205
+ resource_cls = Resolv::DNS::Resource::IN.const_get(type.to_s.upcase)
206
+ resources = answers.map do |answer|
207
+ resource_cls.new(*answer)
208
+ end
209
+ match(query, resource_cls) do |req|
210
+ req.add(resources)
211
+ end
212
+ end
213
+
214
+ semaphore.signal
215
+ end
216
+ end
217
+
218
+ semaphore.wait
219
+
220
+ begin
221
+ yield
222
+ ensure
223
+ 10.times do
224
+ if $last_async_task
225
+ break
226
+ end
227
+ sleep 0.5
228
+ end
229
+
230
+ # Hack to stop the server - https://github.com/socketry/rubydns/issues/75
231
+ if $last_async_task.nil?
232
+ STDERR.puts "No async task - server never started?"
233
+ else
234
+ $last_async_task.stop
235
+ end
236
+
237
+ thread.kill
238
+ thread.join
239
+ end
240
+ end
141
241
  end
142
242
  end
@@ -158,6 +158,14 @@ module Constraints
158
158
  end
159
159
  end
160
160
 
161
+ def require_multi_shard
162
+ before do
163
+ if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length == 1
164
+ skip 'Test requires a minimum of two shards if run in sharded topology'
165
+ end
166
+ end
167
+ end
168
+
161
169
  def require_no_multi_shard
162
170
  before do
163
171
  if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length > 1
@@ -191,4 +199,21 @@ module Constraints
191
199
  end
192
200
  end
193
201
  end
202
+
203
+ # Integration tests for SRV polling require internet connectivity to
204
+ # look up SRV records and a sharded cluster configured on default port on
205
+ # localhost (localhost:27017, localhost:27018).
206
+ def require_default_port_deployment
207
+ # Because the DNS records at test1.test.build.10gen.cc point to
208
+ # localhost:27017 & localhost:27018, the test suite must have been
209
+ # configured to use these addresses
210
+ before(:all) do
211
+ have_default_port = SpecConfig.instance.addresses.any? do |address|
212
+ %w(127.0.0.1 127.0.0.1:27017 localhost localhost:27017).include?(address)
213
+ end
214
+ unless have_default_port
215
+ skip 'This test requires the test suite to be configured for localhost:27017'
216
+ end
217
+ end
218
+ end
194
219
  end
@@ -0,0 +1,13 @@
1
+ require 'rubydns'
2
+
3
+ # Hack to stop the server - https://github.com/socketry/rubydns/issues/75
4
+ module Async
5
+ class Task
6
+ alias :run_without_record :run
7
+ def run(*args)
8
+ run_without_record.tap do
9
+ $last_async_task = self
10
+ end
11
+ end
12
+ end
13
+ end
@@ -44,13 +44,6 @@ class EventSubscriber
44
44
  end
45
45
  end
46
46
 
47
- # Filters command started events for the specified command name.
48
- def command_started_events(command_name)
49
- started_events.select do |event|
50
- event.command[command_name]
51
- end
52
- end
53
-
54
47
  # Locates command stated events for the specified command name,
55
48
  # asserts that there is exactly one such event, and returns it.
56
49
  def single_command_started_event(command_name)
@@ -1,8 +1,12 @@
1
1
  class JsonExtFormatter < RSpec::Core::Formatters::JsonFormatter
2
- RSpec::Core::Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close
2
+ RSpec::Core::Formatters.register self, :message,
3
+ :dump_summary, :dump_profile, :stop, :seed, :close
3
4
 
4
5
  def format_example(example)
5
6
  super.tap do |hash|
7
+ # Time format is chosen to be the same as driver's log entries
8
+ hash[:started_at] = example.execution_result.started_at.strftime('%Y-%m-%d %H:%M:%S.%L %z')
9
+ hash[:finished_at] = example.execution_result.finished_at.strftime('%Y-%m-%d %H:%M:%S.%L %z')
6
10
  hash[:sdam_log_entries] = SdamFormatterIntegration.example_log_entries(example.id)
7
11
  end
8
12
  end
@@ -1,7 +1,7 @@
1
1
  module LiteConstraints
2
2
  # Constrain tests that use TimeoutInterrupt to MRI (and Unix)
3
3
  def only_mri
4
- before do
4
+ before(:all) do
5
5
  unless SpecConfig.instance.mri?
6
6
  skip "MRI required, we have #{SpecConfig.instance.platform}"
7
7
  end
@@ -12,22 +12,38 @@ module LiteConstraints
12
12
  # in principle work (as opposed to being fundamentally incompatible
13
13
  # with jruby).
14
14
  # Often times these failures happen only in Evergreen.
15
- def fails_on_jruby
16
- before do
17
- unless SpecConfig.instance.mri?
18
- skip "Fails on jruby"
15
+ def fails_on_jruby(version=nil)
16
+ before(:all) do
17
+ if BSON::Environment.jruby?
18
+ if version
19
+ min_parts = version.split('.').map(&:to_i)
20
+ actual_parts = JRUBY_VERSION.split('.').map(&:to_i)[0...min_parts.length]
21
+ actual = actual_parts.join('.')
22
+ if actual <= version
23
+ skip "Fails on jruby through #{version}"
24
+ end
25
+ else
26
+ skip "Fails on jruby"
27
+ end
19
28
  end
20
29
  end
21
30
  end
22
31
 
23
32
  def require_external_connectivity
24
- before do
33
+ before(:all) do
25
34
  if ENV['EXTERNAL_DISABLED']
26
35
  skip "Test requires external connectivity"
27
36
  end
28
37
  end
29
38
  end
30
39
 
40
+ def require_mongo_kerberos
41
+ before(:all) do
42
+ skip 'KERBEROS_REQUIRED env var not specified' unless ENV['KERBEROS_REQUIRED']
43
+ require 'mongo_kerberos'
44
+ end
45
+ end
46
+
31
47
  def require_linting
32
48
  before do
33
49
  unless Mongo::Lint.enabled?
@@ -0,0 +1,34 @@
1
+ require 'singleton'
2
+
3
+ class LocalResourceRegistry
4
+ include Singleton
5
+
6
+ def initialize
7
+ @resources = []
8
+ end
9
+
10
+ def register(resource, finalizer)
11
+ @resources << [resource, finalizer]
12
+ # Return resource for chaining
13
+ resource
14
+ end
15
+
16
+ def unregister(resource)
17
+ @resources.delete_if do |_resource, finalizer|
18
+ _resource == resource
19
+ end
20
+ end
21
+
22
+ def close_all
23
+ @resources.each do |resource, finalizer|
24
+ if finalizer.is_a?(Symbol)
25
+ resource.send(finalizer)
26
+ elsif finalizer.is_a?(Proc)
27
+ finalizer.call(resource)
28
+ else
29
+ raise "Unknown finalizer: #{finalizer}"
30
+ end
31
+ end
32
+ @resources = []
33
+ end
34
+ end
@@ -13,8 +13,123 @@
13
13
  # limitations under the License.
14
14
  #
15
15
 
16
+ RSpec::Matchers.define :match_topology_opening_event do |expectation|
17
+
18
+ match do |event|
19
+ event.is_a?(Mongo::Monitoring::Event::TopologyOpening) &&
20
+ event.topology != nil
21
+ end
22
+ end
23
+
24
+ RSpec::Matchers.define :match_topology_description_changed_event do |expectation|
25
+ include Mongo::SDAMMonitoring::Matchable
26
+
27
+ match do |event|
28
+ event.is_a?(Mongo::Monitoring::Event::TopologyChanged) &&
29
+ topologies_match?(event, expectation)
30
+ end
31
+ end
32
+
33
+ RSpec::Matchers.define :match_server_opening_event do |expectation|
34
+
35
+ match do |event|
36
+ event.is_a?(Mongo::Monitoring::Event::ServerOpening) &&
37
+ event.address.to_s == expectation.data['address']
38
+ end
39
+ end
40
+
41
+ RSpec::Matchers.define :match_server_description_changed_event do |expectation|
42
+ include Mongo::SDAMMonitoring::Matchable
43
+
44
+ match do |event|
45
+ event.is_a?(Mongo::Monitoring::Event::ServerDescriptionChanged) &&
46
+ descriptions_match?(event, expectation)
47
+ end
48
+ end
49
+
50
+ RSpec::Matchers.define :match_server_closed_event do |expectation|
51
+
52
+ match do |event|
53
+ event.is_a?(Mongo::Monitoring::Event::ServerClosed) &&
54
+ event.address.to_s == expectation.data['address']
55
+ end
56
+ end
57
+
58
+ RSpec::Matchers.define :match_sdam_monitoring_event do |expectation|
59
+
60
+ match do |event|
61
+ expect(event).to send("match_#{expectation.name}", expectation)
62
+ end
63
+ end
64
+
16
65
  module Mongo
17
66
  module SDAMMonitoring
67
+ module Matchable
68
+
69
+ def descriptions_match?(event, expectation)
70
+ description_matches?(event.previous_description, expectation.data['previousDescription']) &&
71
+ description_matches?(event.new_description, expectation.data['newDescription'])
72
+ end
73
+
74
+ def topologies_match?(event, expectation)
75
+ unless topology_matches?(event.previous_topology, expectation.data['previousDescription'])
76
+ if ENV['VERBOSE_MATCHERS']
77
+ $stderr.puts "Previous topology mismatch"
78
+ end
79
+ return false
80
+ end
81
+ unless topology_matches?(event.new_topology, expectation.data['newDescription'])
82
+ if ENV['VERBOSE_MATCHERS']
83
+ $stderr.puts "New topology mismatch:\nHave: #{event.new_topology}\nWant: #{expectation.data['newDescription']}"
84
+ end
85
+ return false
86
+ end
87
+ true
88
+ end
89
+
90
+ def description_matches?(actual, expected)
91
+ type_ok = case expected['type']
92
+ when 'Standalone' then actual.standalone?
93
+ when 'RSPrimary' then actual.primary?
94
+ when 'RSSecondary' then actual.secondary?
95
+ when 'RSArbiter' then actual.arbiter?
96
+ when 'Mongos' then actual.mongos?
97
+ when 'Unknown' then actual.unknown?
98
+ when 'PossiblePrimary' then actual.unknown?
99
+ when 'RSGhost' then actual.ghost?
100
+ when 'RSOther' then actual.other?
101
+ end
102
+ return false unless type_ok
103
+
104
+ return false if actual.address.to_s != expected['address']
105
+ return false if actual.arbiters != expected['arbiters']
106
+ return false if actual.hosts != expected['hosts']
107
+ return false if actual.passives != expected['passives']
108
+ return false if actual.primary_host != expected['primary']
109
+ return false if actual.replica_set_name != expected['setName']
110
+ true
111
+ end
112
+
113
+ def topology_matches?(actual, expected)
114
+ expected_type = ::Mongo::Cluster::Topology.const_get(expected['topologyType'])
115
+ return false unless actual.is_a?(expected_type)
116
+
117
+ return false unless actual.replica_set_name == expected['setName']
118
+
119
+ expected['servers'].each do |server|
120
+ desc = actual.server_descriptions[server['address'].to_s]
121
+ return false unless description_matches?(desc, server)
122
+ end
123
+
124
+ actual.server_descriptions.keys.each do |address_str|
125
+ unless expected['servers'].any? { |server| server['address'] == address_str }
126
+ return false
127
+ end
128
+ end
129
+
130
+ true
131
+ end
132
+ end
18
133
 
19
134
  # Test subscriber for SDAM monitoring.
20
135
  #