bson 4.13.0-java → 4.15.0-java
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/lib/bson/big_decimal.rb +67 -0
- data/lib/bson/dbref.rb +31 -4
- data/lib/bson/decimal128/builder.rb +9 -5
- data/lib/bson/decimal128.rb +29 -5
- data/lib/bson/float.rb +1 -1
- data/lib/bson/version.rb +1 -1
- data/lib/bson-ruby.jar +0 -0
- data/lib/bson.rb +2 -1
- data/spec/bson/big_decimal_spec.rb +316 -0
- data/spec/bson/dbref_legacy_spec.rb +169 -0
- data/spec/bson/dbref_spec.rb +26 -0
- data/spec/bson/decimal128_spec.rb +231 -0
- data/spec/bson/hash_spec.rb +32 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/cluster_config.rb +14 -4
- data/spec/shared/lib/mrss/constraints.rb +51 -11
- data/spec/shared/lib/mrss/docker_runner.rb +8 -2
- data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
- data/spec/shared/lib/mrss/spec_organizer.rb +29 -2
- data/spec/shared/share/Dockerfile.erb +147 -40
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/distro.sh +2 -1
- data/spec/shared/shlib/server.sh +100 -23
- data/spec/shared/shlib/set_env.sh +9 -6
- data/spec/spec_helper.rb +7 -0
- data/spec/spec_tests/common_driver_spec.rb +2 -1
- data.tar.gz.sig +0 -0
- metadata +36 -20
- metadata.gz.sig +0 -0
@@ -52,7 +52,7 @@ module Mrss
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def require_topology(*topologies)
|
55
|
-
invalid_topologies = topologies - [:single, :replica_set, :sharded]
|
55
|
+
invalid_topologies = topologies - [:single, :replica_set, :sharded, :load_balanced]
|
56
56
|
|
57
57
|
unless invalid_topologies.empty?
|
58
58
|
raise ArgumentError, "Invalid topologies requested: #{invalid_topologies.join(', ')}"
|
@@ -82,7 +82,7 @@ module Mrss
|
|
82
82
|
unless ClusterConfig.instance.server_version >= '4.0'
|
83
83
|
skip 'Transactions tests in a replica set topology require server 4.0+'
|
84
84
|
end
|
85
|
-
when :sharded
|
85
|
+
when :sharded, :load_balanced
|
86
86
|
unless ClusterConfig.instance.server_version >= '4.2'
|
87
87
|
skip 'Transactions tests in a sharded cluster topology require server 4.2+'
|
88
88
|
end
|
@@ -113,6 +113,14 @@ module Mrss
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
+
def require_retry_writes
|
117
|
+
before(:all) do
|
118
|
+
unless SpecConfig.instance.retry_writes?
|
119
|
+
skip "Retry writes is disabled"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
116
124
|
def require_no_retry_writes
|
117
125
|
before(:all) do
|
118
126
|
if SpecConfig.instance.retry_writes?
|
@@ -215,7 +223,8 @@ module Mrss
|
|
215
223
|
|
216
224
|
def require_no_auth
|
217
225
|
before(:all) do
|
218
|
-
|
226
|
+
auth = ENV.fetch('AUTH', '')
|
227
|
+
if (!auth.empty? && auth != 'noauth') || SpecConfig.instance.user || ClusterConfig.instance.auth_enabled?
|
219
228
|
skip "Auth not allowed"
|
220
229
|
end
|
221
230
|
end
|
@@ -241,31 +250,52 @@ module Mrss
|
|
241
250
|
# (mongos 4.0+ overrides the write concern)
|
242
251
|
def require_set_write_concern
|
243
252
|
before(:all) do
|
244
|
-
if ClusterConfig.instance.topology
|
253
|
+
if %i(sharded load_balanced).include?(ClusterConfig.instance.topology) &&
|
254
|
+
ClusterConfig.instance.short_server_version >= '4.0'
|
255
|
+
then
|
245
256
|
skip "mongos 4.0+ overrides write concern"
|
246
257
|
end
|
247
258
|
end
|
248
259
|
end
|
249
260
|
|
250
|
-
def
|
261
|
+
def require_multi_mongos
|
251
262
|
before(:all) do
|
252
263
|
if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length == 1
|
253
|
-
skip 'Test requires a minimum of two
|
264
|
+
skip 'Test requires a minimum of two mongoses if run in sharded topology'
|
265
|
+
end
|
266
|
+
|
267
|
+
if ClusterConfig.instance.topology == :load_balanced && SpecConfig.instance.single_mongos?
|
268
|
+
skip 'Test requires a minimum of two mongoses if run in load-balanced topology'
|
254
269
|
end
|
255
270
|
end
|
256
271
|
end
|
257
272
|
|
258
|
-
|
273
|
+
# In sharded topology operations are distributed to the mongoses.
|
274
|
+
# When we set fail points, the fail point may be set on one mongos and
|
275
|
+
# operation may be executed on another mongos, causing failures.
|
276
|
+
# Tests that are not setting targeted fail points should utilize this
|
277
|
+
# method to restrict themselves to single mongos.
|
278
|
+
#
|
279
|
+
# In load-balanced topology, the same problem can happen when there is
|
280
|
+
# more than one mongos behind the load balancer.
|
281
|
+
def require_no_multi_mongos
|
259
282
|
before(:all) do
|
260
283
|
if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length > 1
|
261
|
-
skip 'Test requires a single
|
284
|
+
skip 'Test requires a single mongos if run in sharded topology'
|
285
|
+
end
|
286
|
+
if ClusterConfig.instance.topology == :load_balanced && !SpecConfig.instance.single_mongos?
|
287
|
+
skip 'Test requires a single mongos, as indicated by SINGLE_MONGOS=1 environment variable, if run in load-balanced topology'
|
262
288
|
end
|
263
289
|
end
|
264
290
|
end
|
265
291
|
|
292
|
+
alias :require_no_multi_shard :require_no_multi_mongos
|
293
|
+
|
266
294
|
def require_wired_tiger
|
267
295
|
before(:all) do
|
268
|
-
|
296
|
+
# Storage detection fails for serverless instances. However, it is safe to
|
297
|
+
# assume that a serverless instance uses WiredTiger Storage Engine.
|
298
|
+
if !SpecConfig.instance.serverless? && ClusterConfig.instance.storage_engine != :wired_tiger
|
269
299
|
skip 'Test requires WiredTiger storage engine'
|
270
300
|
end
|
271
301
|
end
|
@@ -274,7 +304,9 @@ module Mrss
|
|
274
304
|
def require_wired_tiger_on_36
|
275
305
|
before(:all) do
|
276
306
|
if ClusterConfig.instance.short_server_version >= '3.6'
|
277
|
-
|
307
|
+
# Storage detection fails for serverless instances. However, it is safe to
|
308
|
+
# assume that a serverless instance uses WiredTiger Storage Engine.
|
309
|
+
if !SpecConfig.instance.serverless? && ClusterConfig.instance.storage_engine != :wired_tiger
|
278
310
|
skip 'Test requires WiredTiger storage engine on 3.6+ servers'
|
279
311
|
end
|
280
312
|
end
|
@@ -283,7 +315,7 @@ module Mrss
|
|
283
315
|
|
284
316
|
def require_mmapv1
|
285
317
|
before(:all) do
|
286
|
-
if ClusterConfig.instance.storage_engine != :mmapv1
|
318
|
+
if SpecConfig.instance.serverless? || ClusterConfig.instance.storage_engine != :mmapv1
|
287
319
|
skip 'Test requires MMAPv1 storage engine'
|
288
320
|
end
|
289
321
|
end
|
@@ -342,5 +374,13 @@ module Mrss
|
|
342
374
|
end
|
343
375
|
end
|
344
376
|
end
|
377
|
+
|
378
|
+
def require_unix_socket
|
379
|
+
before(:all) do
|
380
|
+
if ENV['TOPOLOGY'] == 'load-balanced'
|
381
|
+
skip 'Load balancer does not listen on Unix sockets'
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
345
385
|
end
|
346
386
|
end
|
@@ -111,7 +111,7 @@ module Mrss
|
|
111
111
|
'.'])
|
112
112
|
end
|
113
113
|
|
114
|
-
BASE_TEST_COMMAND = %w(docker run -i --tmpfs /tmpfs:exec).freeze
|
114
|
+
BASE_TEST_COMMAND = %w(docker run --rm -i --tmpfs /tmpfs:exec).freeze
|
115
115
|
|
116
116
|
def run_tests
|
117
117
|
run_command(BASE_TEST_COMMAND + tty_arg + extra_env + [image_tag] +
|
@@ -173,15 +173,17 @@ module Mrss
|
|
173
173
|
end
|
174
174
|
|
175
175
|
def distro
|
176
|
-
@options[:distro] || '
|
176
|
+
@options[:distro] || 'ubuntu1804'
|
177
177
|
end
|
178
178
|
|
179
179
|
BASE_IMAGES = {
|
180
180
|
'debian81' => 'debian:jessie',
|
181
181
|
'debian92' => 'debian:stretch',
|
182
|
+
'debian10' => 'debian:buster',
|
182
183
|
'ubuntu1404' => 'ubuntu:trusty',
|
183
184
|
'ubuntu1604' => 'ubuntu:xenial',
|
184
185
|
'ubuntu1804' => 'ubuntu:bionic',
|
186
|
+
'ubuntu2004' => 'ubuntu:focal',
|
185
187
|
'rhel62' => 'centos:6',
|
186
188
|
'rhel70' => 'centos:7',
|
187
189
|
}.freeze
|
@@ -198,6 +200,10 @@ module Mrss
|
|
198
200
|
ruby == 'ruby-head'
|
199
201
|
end
|
200
202
|
|
203
|
+
def system_ruby?
|
204
|
+
%w(1 true yes).include?(@env['SYSTEM_RUBY']&.downcase)
|
205
|
+
end
|
206
|
+
|
201
207
|
def server_version
|
202
208
|
@env['MONGODB_VERSION']
|
203
209
|
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mrss
|
4
|
+
# Test event subscriber.
|
5
|
+
class EventSubscriber
|
6
|
+
|
7
|
+
# The mappings of event names to types.
|
8
|
+
MAPPINGS = {
|
9
|
+
'topology_opening_event' => Mongo::Monitoring::Event::TopologyOpening,
|
10
|
+
'topology_description_changed_event' => Mongo::Monitoring::Event::TopologyChanged,
|
11
|
+
'topology_closed_event' => Mongo::Monitoring::Event::TopologyClosed,
|
12
|
+
'server_opening_event' => Mongo::Monitoring::Event::ServerOpening,
|
13
|
+
'server_description_changed_event' => Mongo::Monitoring::Event::ServerDescriptionChanged,
|
14
|
+
'server_closed_event' => Mongo::Monitoring::Event::ServerClosed
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
attr_reader :all_events
|
18
|
+
|
19
|
+
attr_reader :started_events
|
20
|
+
|
21
|
+
attr_reader :succeeded_events
|
22
|
+
|
23
|
+
attr_reader :failed_events
|
24
|
+
|
25
|
+
attr_reader :published_events
|
26
|
+
|
27
|
+
# @param [ String ] name Optional name for the event subscriber.
|
28
|
+
def initialize(name: nil)
|
29
|
+
@mutex = Mutex.new
|
30
|
+
clear_events!
|
31
|
+
@name = name
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
%Q`#<EventSubscriber:#{@name ? "\"#{@name}\"" : '%x' % object_id} \
|
36
|
+
started=#{started_events.length} \
|
37
|
+
succeeded=#{succeeded_events.length} \
|
38
|
+
failed=#{failed_events.length} \
|
39
|
+
published=#{published_events.length}>`
|
40
|
+
end
|
41
|
+
|
42
|
+
alias :inspect :to_s
|
43
|
+
|
44
|
+
# Event retrieval
|
45
|
+
|
46
|
+
def select_started_events(cls)
|
47
|
+
started_events.select do |event|
|
48
|
+
event.is_a?(cls)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def select_succeeded_events(cls)
|
53
|
+
succeeded_events.select do |event|
|
54
|
+
event.is_a?(cls)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def select_completed_events(*classes)
|
59
|
+
(succeeded_events + failed_events).select do |event|
|
60
|
+
classes.any? { |c| c === event }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def select_published_events(cls)
|
65
|
+
published_events.select do |event|
|
66
|
+
event.is_a?(cls)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Filters command started events for the specified command name.
|
71
|
+
def command_started_events(command_name)
|
72
|
+
started_events.select do |event|
|
73
|
+
event.command[command_name]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def non_auth_command_started_events
|
78
|
+
started_events.reject do |event|
|
79
|
+
%w(authenticate getnonce saslSstart saslContinue).any? do |cmd|
|
80
|
+
event.command[cmd]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Locates command stated events for the specified command name,
|
86
|
+
# asserts that there is exactly one such event, and returns it.
|
87
|
+
def single_command_started_event(command_name, include_auth: false)
|
88
|
+
events = if include_auth
|
89
|
+
started_events
|
90
|
+
else
|
91
|
+
non_auth_command_started_events
|
92
|
+
end
|
93
|
+
events.select! do |event|
|
94
|
+
event.command[command_name]
|
95
|
+
end
|
96
|
+
if events.length != 1
|
97
|
+
raise "Expected a single #{command_name} event but we have #{events.length}"
|
98
|
+
end
|
99
|
+
events.first
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Get the first succeeded event published for the name, and then delete it.
|
104
|
+
#
|
105
|
+
# @param [ String ] name The event name.
|
106
|
+
#
|
107
|
+
# @return [ Event ] The matching event.
|
108
|
+
def first_event(name)
|
109
|
+
cls = MAPPINGS[name]
|
110
|
+
if cls.nil?
|
111
|
+
raise ArgumentError, "Bogus event name #{name}"
|
112
|
+
end
|
113
|
+
matching = succeeded_events.find do |event|
|
114
|
+
cls === event
|
115
|
+
end
|
116
|
+
succeeded_events.delete(matching)
|
117
|
+
matching
|
118
|
+
end
|
119
|
+
|
120
|
+
# Event recording
|
121
|
+
|
122
|
+
# Cache the started event.
|
123
|
+
#
|
124
|
+
# @param [ Event ] event The event.
|
125
|
+
def started(event)
|
126
|
+
@mutex.synchronize do
|
127
|
+
started_events << event
|
128
|
+
all_events << event
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Cache the succeeded event.
|
133
|
+
#
|
134
|
+
# @param [ Event ] event The event.
|
135
|
+
def succeeded(event)
|
136
|
+
@mutex.synchronize do
|
137
|
+
succeeded_events << event
|
138
|
+
all_events << event
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Cache the failed event.
|
143
|
+
#
|
144
|
+
# @param [ Event ] event The event.
|
145
|
+
def failed(event)
|
146
|
+
@mutex.synchronize do
|
147
|
+
failed_events << event
|
148
|
+
all_events << event
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def published(event)
|
153
|
+
@mutex.synchronize do
|
154
|
+
published_events << event
|
155
|
+
all_events << event
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Clear all cached events.
|
160
|
+
def clear_events!
|
161
|
+
@all_events = []
|
162
|
+
@started_events = []
|
163
|
+
@succeeded_events = []
|
164
|
+
@failed_events = []
|
165
|
+
@published_events = []
|
166
|
+
self
|
167
|
+
end
|
168
|
+
end
|
169
|
+
# Only handles succeeded events correctly.
|
170
|
+
class PhasedEventSubscriber < EventSubscriber
|
171
|
+
def initialize
|
172
|
+
super
|
173
|
+
@phase_events = {}
|
174
|
+
end
|
175
|
+
|
176
|
+
def phase_finished(phase_index)
|
177
|
+
@phase_events[phase_index] = succeeded_events
|
178
|
+
@succeeded_events = []
|
179
|
+
end
|
180
|
+
|
181
|
+
def phase_events(phase_index)
|
182
|
+
@phase_events[phase_index]
|
183
|
+
end
|
184
|
+
|
185
|
+
def event_count
|
186
|
+
@phase_events.inject(0) do |sum, event|
|
187
|
+
sum + event.length
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class VerboseEventSubscriber < EventSubscriber
|
193
|
+
%w(started succeeded failed published).each do |meth|
|
194
|
+
define_method(meth) do |event|
|
195
|
+
puts event.summary
|
196
|
+
super(event)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -48,19 +48,24 @@ module Mrss
|
|
48
48
|
url = dl['archive']['url']
|
49
49
|
end
|
50
50
|
rescue MissingDownloadUrl
|
51
|
-
if %w(
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
ensure
|
61
|
-
io.close
|
62
|
-
end
|
51
|
+
if %w(2.6 3.0).include?(desired_version) && arch == 'ubuntu1604'
|
52
|
+
# 2.6 and 3.0 are only available for ubuntu1204 and ubuntu1404.
|
53
|
+
# Those ubuntus have ancient Pythons that don't work due to not
|
54
|
+
# implementing recent TLS protocols.
|
55
|
+
# Because of this we test on ubuntu1604 which has a newer Python.
|
56
|
+
# But we still need to retrieve ubuntu1404-targeting builds.
|
57
|
+
url = self.class.new('3.2', arch).download_url
|
58
|
+
unless url.include?('3.2.')
|
59
|
+
raise 'URL not in expected format'
|
63
60
|
end
|
61
|
+
url = case desired_version
|
62
|
+
when '2.6'
|
63
|
+
url.sub(/\b3\.2\.\d+/, '2.6.12')
|
64
|
+
when '3.0'
|
65
|
+
url.sub(/\b3\.2\.\d+/, '3.0.15')
|
66
|
+
else
|
67
|
+
raise NotImplementedError
|
68
|
+
end.sub('ubuntu1604', 'ubuntu1404')
|
64
69
|
else
|
65
70
|
raise
|
66
71
|
end
|
@@ -25,18 +25,28 @@ module Mrss
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def initialize(root: nil, classifiers:, priority_order:,
|
28
|
-
spec_root: nil, rspec_json_path: nil, rspec_all_json_path: nil
|
28
|
+
spec_root: nil, rspec_json_path: nil, rspec_all_json_path: nil,
|
29
|
+
randomize: false
|
29
30
|
)
|
30
31
|
@spec_root = spec_root || File.join(root, 'spec')
|
31
32
|
@classifiers = classifiers
|
32
33
|
@priority_order = priority_order
|
33
34
|
@rspec_json_path = rspec_json_path || File.join(root, 'tmp/rspec.json')
|
34
35
|
@rspec_all_json_path = rspec_all_json_path || File.join(root, 'tmp/rspec-all.json')
|
36
|
+
@randomize = !!randomize
|
35
37
|
end
|
36
38
|
|
37
39
|
attr_reader :spec_root, :classifiers, :priority_order
|
38
40
|
attr_reader :rspec_json_path, :rspec_all_json_path
|
39
41
|
|
42
|
+
def randomize?
|
43
|
+
@randomize
|
44
|
+
end
|
45
|
+
|
46
|
+
def seed
|
47
|
+
@seed ||= (rand * 100_000).to_i
|
48
|
+
end
|
49
|
+
|
40
50
|
def buckets
|
41
51
|
@buckets ||= {}.tap do |buckets|
|
42
52
|
Find.find(spec_root) do |path|
|
@@ -81,10 +91,20 @@ module Mrss
|
|
81
91
|
end
|
82
92
|
|
83
93
|
def run
|
94
|
+
run_buckets(*buckets.keys)
|
95
|
+
end
|
96
|
+
|
97
|
+
def run_buckets(*buckets)
|
84
98
|
FileUtils.rm_f(rspec_all_json_path)
|
85
99
|
|
100
|
+
buckets.each do |bucket|
|
101
|
+
if bucket && !self.buckets[bucket]
|
102
|
+
raise "Unknown bucket #{bucket}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
buckets = Hash[self.buckets.select { |k, v| buckets.include?(k) }]
|
106
|
+
|
86
107
|
failed = []
|
87
|
-
buckets = self.buckets.dup
|
88
108
|
|
89
109
|
priority_order.each do |category|
|
90
110
|
if files = buckets.delete(category)
|
@@ -112,8 +132,12 @@ module Mrss
|
|
112
132
|
puts "Running #{category.to_s.gsub('_', ' ')} tests"
|
113
133
|
FileUtils.rm_f(rspec_json_path)
|
114
134
|
cmd = %w(rspec) + paths
|
135
|
+
if randomize?
|
136
|
+
cmd += %W(--order rand:#{seed})
|
137
|
+
end
|
115
138
|
|
116
139
|
begin
|
140
|
+
puts "Running #{cmd.join(' ')}"
|
117
141
|
ChildProcessHelper.check_call(cmd)
|
118
142
|
ensure
|
119
143
|
if File.exist?(rspec_json_path)
|
@@ -139,6 +163,9 @@ module Mrss
|
|
139
163
|
end
|
140
164
|
new.delete('version')
|
141
165
|
new.delete('summary_line')
|
166
|
+
# The spec organizer runs all buckets with the same seed, hence
|
167
|
+
# we can drop the seed from new results.
|
168
|
+
new.delete('seed')
|
142
169
|
unless new.empty?
|
143
170
|
raise "Unhandled rspec results keys: #{new.keys.join(', ')}"
|
144
171
|
end
|