mongo 2.10.5 → 2.11.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
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
  #