bson 4.15.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/README.md +4 -4
  4. data/Rakefile +5 -0
  5. data/ext/bson/bson-native.h +12 -4
  6. data/ext/bson/extconf.rb +8 -3
  7. data/ext/bson/init.c +11 -11
  8. data/ext/bson/read.c +21 -6
  9. data/ext/bson/util.c +168 -16
  10. data/ext/bson/write.c +30 -39
  11. data/lib/bson/active_support.rb +1 -0
  12. data/lib/bson/array.rb +57 -31
  13. data/lib/bson/big_decimal.rb +16 -6
  14. data/lib/bson/binary.rb +255 -128
  15. data/lib/bson/boolean.rb +1 -0
  16. data/lib/bson/code.rb +9 -11
  17. data/lib/bson/code_with_scope.rb +8 -10
  18. data/lib/bson/config.rb +1 -27
  19. data/lib/bson/date.rb +2 -1
  20. data/lib/bson/date_time.rb +2 -1
  21. data/lib/bson/db_pointer.rb +11 -12
  22. data/lib/bson/dbref.rb +11 -9
  23. data/lib/bson/decimal128/builder.rb +9 -8
  24. data/lib/bson/decimal128.rb +24 -110
  25. data/lib/bson/document.rb +1 -0
  26. data/lib/bson/environment.rb +1 -0
  27. data/lib/bson/error/bson_decode_error.rb +11 -0
  28. data/lib/bson/error/ext_json_parse_error.rb +11 -0
  29. data/lib/bson/error/illegal_key.rb +23 -0
  30. data/lib/bson/error/invalid_binary_type.rb +37 -0
  31. data/lib/bson/error/invalid_dbref_argument.rb +12 -0
  32. data/lib/bson/error/invalid_decimal128_argument.rb +25 -0
  33. data/lib/bson/error/invalid_decimal128_range.rb +27 -0
  34. data/lib/bson/error/invalid_decimal128_string.rb +26 -0
  35. data/lib/bson/error/invalid_key.rb +24 -0
  36. data/lib/bson/error/invalid_object_id.rb +11 -0
  37. data/lib/bson/error/invalid_regexp_pattern.rb +13 -0
  38. data/lib/bson/error/unrepresentable_precision.rb +19 -0
  39. data/lib/bson/error/unserializable_class.rb +13 -0
  40. data/lib/bson/error/unsupported_binary_subtype.rb +12 -0
  41. data/lib/bson/error/unsupported_type.rb +11 -0
  42. data/lib/bson/error.rb +16 -28
  43. data/lib/bson/ext_json.rb +1 -0
  44. data/lib/bson/false_class.rb +2 -1
  45. data/lib/bson/float.rb +2 -1
  46. data/lib/bson/hash.rb +127 -72
  47. data/lib/bson/int32.rb +16 -4
  48. data/lib/bson/int64.rb +16 -4
  49. data/lib/bson/integer.rb +3 -4
  50. data/lib/bson/json.rb +1 -0
  51. data/lib/bson/max_key.rb +7 -9
  52. data/lib/bson/min_key.rb +7 -9
  53. data/lib/bson/nil_class.rb +1 -0
  54. data/lib/bson/object.rb +5 -25
  55. data/lib/bson/object_id.rb +75 -121
  56. data/lib/bson/open_struct.rb +3 -2
  57. data/lib/bson/regexp.rb +35 -64
  58. data/lib/bson/registry.rb +2 -6
  59. data/lib/bson/specialized.rb +2 -1
  60. data/lib/bson/string.rb +4 -27
  61. data/lib/bson/symbol.rb +22 -19
  62. data/lib/bson/time.rb +2 -1
  63. data/lib/bson/time_with_zone.rb +13 -1
  64. data/lib/bson/timestamp.rb +2 -1
  65. data/lib/bson/true_class.rb +2 -1
  66. data/lib/bson/undefined.rb +14 -0
  67. data/lib/bson/version.rb +2 -1
  68. data/lib/bson.rb +3 -2
  69. data/spec/bson/array_spec.rb +19 -60
  70. data/spec/bson/big_decimal_spec.rb +16 -4
  71. data/spec/bson/binary_spec.rb +83 -74
  72. data/spec/bson/binary_uuid_spec.rb +1 -0
  73. data/spec/bson/boolean_spec.rb +1 -0
  74. data/spec/bson/byte_buffer_read_spec.rb +1 -0
  75. data/spec/bson/byte_buffer_spec.rb +1 -0
  76. data/spec/bson/byte_buffer_write_spec.rb +1 -0
  77. data/spec/bson/code_spec.rb +5 -3
  78. data/spec/bson/code_with_scope_spec.rb +5 -3
  79. data/spec/bson/config_spec.rb +1 -35
  80. data/spec/bson/date_spec.rb +1 -0
  81. data/spec/bson/date_time_spec.rb +1 -0
  82. data/spec/bson/dbref_legacy_spec.rb +20 -3
  83. data/spec/bson/dbref_spec.rb +9 -9
  84. data/spec/bson/decimal128_spec.rb +40 -20
  85. data/spec/bson/document_as_spec.rb +1 -0
  86. data/spec/bson/document_spec.rb +1 -1
  87. data/spec/bson/ext_json_parse_spec.rb +1 -0
  88. data/spec/bson/false_class_spec.rb +8 -0
  89. data/spec/bson/float_spec.rb +8 -3
  90. data/spec/bson/hash_as_spec.rb +1 -0
  91. data/spec/bson/hash_spec.rb +87 -75
  92. data/spec/bson/int32_spec.rb +21 -6
  93. data/spec/bson/int64_spec.rb +21 -6
  94. data/spec/bson/integer_spec.rb +45 -13
  95. data/spec/bson/json_spec.rb +1 -0
  96. data/spec/bson/max_key_spec.rb +5 -3
  97. data/spec/bson/min_key_spec.rb +5 -3
  98. data/spec/bson/nil_class_spec.rb +1 -0
  99. data/spec/bson/object_id_spec.rb +43 -4
  100. data/spec/bson/object_spec.rb +2 -1
  101. data/spec/bson/open_struct_spec.rb +14 -71
  102. data/spec/bson/raw_spec.rb +9 -15
  103. data/spec/bson/regexp_spec.rb +4 -3
  104. data/spec/bson/registry_spec.rb +2 -1
  105. data/spec/bson/string_spec.rb +13 -38
  106. data/spec/bson/symbol_raw_spec.rb +25 -0
  107. data/spec/bson/symbol_spec.rb +15 -18
  108. data/spec/bson/time_spec.rb +1 -0
  109. data/spec/bson/time_with_zone_spec.rb +1 -0
  110. data/spec/bson/timestamp_spec.rb +1 -0
  111. data/spec/bson/true_class_spec.rb +8 -0
  112. data/spec/bson/undefined_spec.rb +27 -0
  113. data/spec/bson_spec.rb +1 -0
  114. data/spec/runners/common_driver.rb +6 -5
  115. data/spec/runners/corpus.rb +6 -0
  116. data/spec/runners/corpus_legacy.rb +1 -0
  117. data/spec/shared/lib/mrss/constraints.rb +8 -16
  118. data/spec/shared/lib/mrss/docker_runner.rb +30 -3
  119. data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
  120. data/spec/shared/lib/mrss/event_subscriber.rb +15 -5
  121. data/spec/shared/lib/mrss/lite_constraints.rb +48 -1
  122. data/spec/shared/lib/mrss/server_version_registry.rb +16 -23
  123. data/spec/shared/lib/mrss/session_registry.rb +69 -0
  124. data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
  125. data/spec/shared/lib/mrss/utils.rb +28 -6
  126. data/spec/shared/share/Dockerfile.erb +68 -85
  127. data/spec/shared/shlib/config.sh +27 -0
  128. data/spec/shared/shlib/server.sh +73 -24
  129. data/spec/shared/shlib/set_env.sh +39 -1
  130. data/spec/spec_helper.rb +1 -0
  131. data/spec/spec_tests/common_driver_spec.rb +9 -4
  132. data/spec/spec_tests/corpus_legacy_spec.rb +1 -0
  133. data/spec/spec_tests/corpus_spec.rb +13 -3
  134. data/spec/spec_tests/data/corpus/binary.json +5 -0
  135. data/spec/spec_tests/data/corpus/code.json +13 -13
  136. data/spec/spec_tests/data/corpus/decimal128-4.json +48 -0
  137. data/spec/spec_tests/data/corpus/decimal128-6.json +12 -0
  138. data/spec/spec_tests/data/corpus/decimal128-7.json +4 -0
  139. data/spec/spec_tests/data/corpus/document.json +20 -0
  140. data/spec/spec_tests/data/corpus/symbol.json +7 -7
  141. data/spec/spec_tests/data/corpus/top.json +18 -3
  142. data/spec/support/shared_examples.rb +28 -5
  143. data/spec/support/spec_config.rb +1 -0
  144. data/spec/support/utils.rb +49 -1
  145. data.tar.gz.sig +0 -0
  146. metadata +167 -144
  147. metadata.gz.sig +2 -1
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2018-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,4 +26,11 @@ describe TrueClass do
25
26
  it_behaves_like "a bson element"
26
27
  it_behaves_like "a serializable bson element"
27
28
  end
29
+
30
+ describe '#as_extended_json' do
31
+ let(:object) { true }
32
+
33
+ it_behaves_like '#as_extended_json returns self'
34
+ it_behaves_like 'an Extended JSON serializable object'
35
+ end
28
36
  end
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,4 +27,30 @@ describe BSON::Undefined do
26
27
  it_behaves_like "a serializable bson element"
27
28
  it_behaves_like "a deserializable bson element"
28
29
  end
30
+
31
+ describe "#as_json" do
32
+
33
+ let(:object) do
34
+ described_class.new
35
+ end
36
+
37
+ it "returns nil" do
38
+ expect(object.as_json).to eq(nil)
39
+ end
40
+
41
+ it_behaves_like 'a JSON serializable object'
42
+ end
43
+
44
+ describe "#as_extended_json" do
45
+
46
+ let(:object) do
47
+ described_class.new
48
+ end
49
+
50
+ it "returns the binary data plus type" do
51
+ expect(object.as_extended_json).to eq({ "$undefined" => true })
52
+ end
53
+
54
+ it_behaves_like 'an Extended JSON serializable object'
55
+ end
29
56
  end
data/spec/bson_spec.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2009-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2016-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -184,13 +185,13 @@ module BSON
184
185
  # The object as json, in a document with the test key.
185
186
  #
186
187
  # @example Get a document with the object at the test key.
187
- # test.document_as_json
188
+ # test.document_as_extended_json
188
189
  #
189
- # @return [ BSON::Document ] The json document.
190
+ # @return [ Hash ] The extended_json representation of document.
190
191
  #
191
192
  # @since 4.2.0
192
- def document_as_json
193
- { @test_key => object.as_json }
193
+ def document_as_extended_json
194
+ { @test_key => object.as_extended_json }
194
195
  end
195
196
 
196
197
  # Use the string in the extended json to instantiate the bson object.
@@ -340,7 +341,7 @@ module BSON
340
341
  def decoded_document
341
342
  @document ||= (data = [ @subject ].pack('H*')
342
343
  buffer = BSON::ByteBuffer.new(data)
343
- BSON::Document.from_bson(buffer))
344
+ BSON::Document.from_bson(buffer, mode: :bson))
344
345
  end
345
346
  end
346
347
  end
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2016-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -57,6 +58,10 @@ module BSON
57
58
  @spec['test_key']
58
59
  end
59
60
 
61
+ def bson_type
62
+ @bson_type ||= @spec['bson_type'].to_i(16).chr
63
+ end
64
+
60
65
  def valid_tests
61
66
  @valid_tests ||=
62
67
  @spec['valid']&.map do |test_spec|
@@ -179,6 +184,7 @@ module BSON
179
184
  @string = test_params['string']
180
185
  end
181
186
 
187
+ attr_reader :spec
182
188
  attr_reader :description, :string
183
189
  end
184
190
  end
@@ -1,3 +1,4 @@
1
+ # rubocop:todo all
1
2
  # Copyright (C) 2016-2020 MongoDB Inc.
2
3
  #
3
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -4,48 +4,40 @@
4
4
  module Mrss
5
5
  module Constraints
6
6
  def min_server_version(version)
7
- unless version =~ /\A\d+\.\d+\z/
8
- raise ArgumentError, "Version can only be major.minor: #{version}"
9
- end
7
+ parsed_version = Gem::Version.new(version)
10
8
 
11
9
  before(:all) do
12
- if version > ClusterConfig.instance.server_version
10
+ if parsed_version > Gem::Version.new(ClusterConfig.instance.server_version)
13
11
  skip "Server version #{version} or higher required, we have #{ClusterConfig.instance.server_version}"
14
12
  end
15
13
  end
16
14
  end
17
15
 
18
16
  def max_server_version(version)
19
- unless version =~ /\A\d+\.\d+\z/
20
- raise ArgumentError, "Version can only be major.minor: #{version}"
21
- end
17
+ parsed_version = Gem::Version.new(version)
22
18
 
23
19
  before(:all) do
24
- if version < ClusterConfig.instance.short_server_version
20
+ if parsed_version < Gem::Version.new(ClusterConfig.instance.server_version)
25
21
  skip "Server version #{version} or lower required, we have #{ClusterConfig.instance.server_version}"
26
22
  end
27
23
  end
28
24
  end
29
25
 
30
26
  def min_server_fcv(version)
31
- unless version =~ /\A\d+\.\d+\z/
32
- raise ArgumentError, "FCV can only be major.minor: #{version}"
33
- end
27
+ parsed_version = Gem::Version.new(version)
34
28
 
35
29
  before(:all) do
36
- unless ClusterConfig.instance.fcv_ish >= version
30
+ unless Gem::Version.new(ClusterConfig.instance.fcv_ish) >= parsed_version
37
31
  skip "FCV #{version} or higher required, we have #{ClusterConfig.instance.fcv_ish} (server #{ClusterConfig.instance.server_version})"
38
32
  end
39
33
  end
40
34
  end
41
35
 
42
36
  def max_server_fcv(version)
43
- unless version =~ /\A\d+\.\d+\z/
44
- raise ArgumentError, "Version can only be major.minor: #{version}"
45
- end
37
+ parsed_version = Gem::Version.new(version)
46
38
 
47
39
  before(:all) do
48
- if version < ClusterConfig.instance.fcv_ish
40
+ if parsed_version < Gem::Version.new(ClusterConfig.instance.fcv_ish)
49
41
  skip "FCV #{version} or lower required, we have #{ClusterConfig.instance.fcv_ish} (server #{ClusterConfig.instance.server_version})"
50
42
  end
51
43
  end
@@ -16,7 +16,7 @@ module Mrss
16
16
  opts.fetch(:default_script)
17
17
  opts.fetch(:project_lib_subdir)
18
18
 
19
- @options = opts
19
+ @options = opts.merge(preload: true)
20
20
  end
21
21
 
22
22
  attr_reader :options
@@ -63,10 +63,14 @@ module Mrss
63
63
  @options[:mongo_only] = v.to_i
64
64
  end
65
65
 
66
- opts.on('-p', '--preload', 'Preload Ruby toolchain and server binaries in docker') do |v|
66
+ opts.on('-p', '--preload', 'Preload Ruby toolchain and server binaries in docker (default)') do |v|
67
67
  @options[:preload] = v
68
68
  end
69
69
 
70
+ opts.on('-P', '--no-preload', 'Do not preload Ruby toolchain and server binaries in docker') do
71
+ @options[:preload] = false
72
+ end
73
+
70
74
  opts.on('-s', '--script=SCRIPT', 'Test script to invoke') do |v|
71
75
  @options[:script] = v
72
76
  end
@@ -173,19 +177,33 @@ module Mrss
173
177
  end
174
178
 
175
179
  def distro
176
- @options[:distro] || 'ubuntu1804'
180
+ @options[:distro] || if app_tests?
181
+ 'ubuntu2004'
182
+ else
183
+ case server_version
184
+ when '3.6'
185
+ 'debian9'
186
+ when '4.0', '4.2'
187
+ 'ubuntu1804'
188
+ else
189
+ 'ubuntu2004'
190
+ end
191
+ end
177
192
  end
178
193
 
179
194
  BASE_IMAGES = {
180
195
  'debian81' => 'debian:jessie',
181
196
  'debian92' => 'debian:stretch',
182
197
  'debian10' => 'debian:buster',
198
+ 'debian11' => 'debian:bullseye',
183
199
  'ubuntu1404' => 'ubuntu:trusty',
184
200
  'ubuntu1604' => 'ubuntu:xenial',
185
201
  'ubuntu1804' => 'ubuntu:bionic',
186
202
  'ubuntu2004' => 'ubuntu:focal',
203
+ 'ubuntu2204' => 'ubuntu:jammy',
187
204
  'rhel62' => 'centos:6',
188
205
  'rhel70' => 'centos:7',
206
+ 'rhel80' => 'rockylinux:8',
189
207
  }.freeze
190
208
 
191
209
  def base_image
@@ -216,6 +234,10 @@ module Mrss
216
234
  distro =~ /debian|ubuntu/
217
235
  end
218
236
 
237
+ def ubuntu?
238
+ distro=~ /ubuntu/
239
+ end
240
+
219
241
  def preload?
220
242
  !!@options[:preload]
221
243
  end
@@ -253,6 +275,11 @@ module Mrss
253
275
  %w(1 true yes).include?(@env['FLE']&.downcase)
254
276
  end
255
277
 
278
+ # Mongoid
279
+ def app_tests?
280
+ %w(1 true yes).include?(@env['APP_TESTS']&.downcase)
281
+ end
282
+
256
283
  def num_exposed_ports
257
284
  case @env['TOPOLOGY'] || 'standalone'
258
285
  when 'standalone'
@@ -0,0 +1,51 @@
1
+ autoload :YAML, 'yaml'
2
+ require 'erubi'
3
+ require 'erubi/capture_end'
4
+ require 'tilt'
5
+
6
+ module Mrss
7
+ module EgConfigUtils
8
+
9
+ DEBIAN_FOR_RUBY = {
10
+ 'ruby-2.3' => 'debian92',
11
+ 'ruby-2.4' => 'debian92',
12
+ 'ruby-2.5' => 'debian10',
13
+ 'ruby-2.6' => 'debian10',
14
+ 'ruby-2.7' => 'debian10',
15
+ 'ruby-3.0' => 'debian10',
16
+ }
17
+
18
+ def standard_debian_rubies(rubies, key: nil, &block)
19
+ rubies.flatten!
20
+ text = block.call
21
+ contents = YAML.load(text)
22
+ out = rubies.map do |ruby|
23
+ contents.merge(
24
+ 'matrix_name' => "#{contents['matrix_name']} - #{ruby}",
25
+ 'matrix_spec' => contents['matrix_spec'].merge(
26
+ 'ruby' => ruby,
27
+ key || 'os' => DEBIAN_FOR_RUBY.fetch(ruby),
28
+ ),
29
+ )
30
+ end.to_yaml
31
+ text =~ /\A\n?(\s+)/
32
+ unless text
33
+ raise "Couldn't figure out indentation level"
34
+ end
35
+ indent = ' ' * ($1.length - 2)
36
+ "\n" + out.sub(/\A---.*\n/, indent).gsub("\n", "\n#{indent}")
37
+ end
38
+
39
+ def transform_config(template_path, context)
40
+ Tilt.new(template_path, engine_class: Erubi::CaptureEndEngine).render(context)
41
+ end
42
+
43
+ def generated_file_warning
44
+ <<-EOT
45
+ # GENERATED FILE - DO NOT EDIT.
46
+ # Run ./.evergreen/update-evergreen-configs to regenerate this file.
47
+
48
+ EOT
49
+ end
50
+ end
51
+ end
@@ -84,22 +84,32 @@ module Mrss
84
84
 
85
85
  # Locates command stated events for the specified command name,
86
86
  # asserts that there is exactly one such event, and returns it.
87
- def single_command_started_event(command_name, include_auth: false)
87
+ def single_command_started_event(command_name, include_auth: false, database_name: nil)
88
88
  events = if include_auth
89
89
  started_events
90
90
  else
91
91
  non_auth_command_started_events
92
92
  end
93
- events.select! do |event|
94
- event.command[command_name]
93
+ get_one_event(events, command_name, 'started', database_name: database_name)
94
+ end
95
+
96
+ # Locates command succeeded events for the specified command name,
97
+ # asserts that there is exactly one such event, and returns it.
98
+ def single_command_succeeded_event(command_name, database_name: nil)
99
+ get_one_event(succeeded_events, command_name, 'succeeded', database_name: database_name)
100
+ end
101
+
102
+ def get_one_event(events, command_name, kind, database_name: nil)
103
+ events = events.select do |event|
104
+ event.command_name == command_name and
105
+ database_name.nil? || database_name == event.database_name
95
106
  end
96
107
  if events.length != 1
97
- raise "Expected a single #{command_name} event but we have #{events.length}"
108
+ raise "Expected a single '#{command_name}' #{kind} event#{database_name ? " for '#{database_name}'" : ''} but we have #{events.length}"
98
109
  end
99
110
  events.first
100
111
  end
101
112
 
102
-
103
113
  # Get the first succeeded event published for the name, and then delete it.
104
114
  #
105
115
  # @param [ String ] name The event name.
@@ -87,12 +87,25 @@ module Mrss
87
87
 
88
88
  def require_libmongocrypt
89
89
  before(:all) do
90
- unless ENV['LIBMONGOCRYPT_PATH']
90
+ # If FLE is set in environment, the entire test run is supposed to
91
+ # include FLE therefore run the FLE tests.
92
+ if (ENV['LIBMONGOCRYPT_PATH'] || '').empty? && (ENV['FLE'] || '').empty?
91
93
  skip 'Test requires path to libmongocrypt to be specified in LIBMONGOCRYPT_PATH env variable'
92
94
  end
93
95
  end
94
96
  end
95
97
 
98
+ def min_libmongocrypt_version(version)
99
+ require_libmongocrypt
100
+ before(:all) do
101
+ actual_version = Utils.parse_version(Mongo::Crypt::Binding.mongocrypt_version(nil))
102
+ min_version = Utils.parse_version(version)
103
+ unless actual_version >= min_version
104
+ skip "libmongocrypt version #{min_version} required, but version #{actual_version} is available"
105
+ end
106
+ end
107
+ end
108
+
96
109
  def require_no_libmongocrypt
97
110
  before(:all) do
98
111
  if ENV['LIBMONGOCRYPT_PATH']
@@ -187,5 +200,39 @@ module Mrss
187
200
  end
188
201
  end
189
202
  end
203
+
204
+ def require_fallbacks
205
+ before(:all) do
206
+ unless %w(yes true 1).include?((ENV['TEST_I18N_FALLBACKS'] || '').downcase)
207
+ skip 'Set TEST_I18N_FALLBACKS=1 environment variable to run these tests'
208
+ end
209
+ end
210
+ end
211
+
212
+ def require_no_fallbacks
213
+ before(:all) do
214
+ if %w(yes true 1).include?((ENV['TEST_I18N_FALLBACKS'] || '').downcase)
215
+ skip 'Set TEST_I18N_FALLBACKS=0 environment variable to run these tests'
216
+ end
217
+ end
218
+ end
219
+
220
+ # This is a macro for retrying flaky tests on CI that occasionally fail.
221
+ # Note that the tests will only be retried on CI.
222
+ #
223
+ # @param [ Integer ] :tries The number of times to retry.
224
+ # @param [ Integer ] :sleep The number of seconds to sleep in between retries.
225
+ # If nothing, or nil, is passed, we won't wait in between retries.
226
+ def retry_test(tries: 3, sleep: nil)
227
+ if %w(1 yes true).include?(ENV['CI'])
228
+ around do |example|
229
+ if sleep
230
+ example.run_with_retry retry: tries, retry_wait: sleep
231
+ else
232
+ example.run_with_retry retry: tries
233
+ end
234
+ end
235
+ end
236
+ end
190
237
  end
191
238
  end
@@ -24,6 +24,21 @@ module Mrss
24
24
 
25
25
  attr_reader :desired_version, :arch
26
26
 
27
+ def target_arch
28
+ # can't use RbConfig::CONFIG["arch"] because JRuby doesn't
29
+ # return anything meaningful there.
30
+ #
31
+ # also, need to use `uname -a` instead of (e.g.) `uname -p`
32
+ # because debian (at least) does not return anything meaningful
33
+ # for `uname -p`.
34
+ uname = `uname -a`.strip
35
+ @target_arch ||= case uname
36
+ when /aarch/ then "aarch64"
37
+ when /x86/ then "x86_64"
38
+ else raise "unsupported architecture #{uname.inspect}"
39
+ end
40
+ end
41
+
27
42
  def download_url
28
43
  @download_url ||= begin
29
44
  version, version_ok = detect_version(current_catalog)
@@ -40,35 +55,13 @@ module Mrss
40
55
  end
41
56
  dl = version['downloads'].detect do |dl|
42
57
  dl['archive']['url'].index("enterprise-#{arch}") &&
43
- dl['arch'] == 'x86_64'
58
+ dl['arch'] == target_arch
44
59
  end
45
60
  unless dl
46
61
  raise MissingDownloadUrl, "No download for #{arch} for #{version['version']}"
47
62
  end
48
63
  url = dl['archive']['url']
49
64
  end
50
- rescue MissingDownloadUrl
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'
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')
69
- else
70
- raise
71
- end
72
65
  end
73
66
 
74
67
  private
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'singleton'
5
+
6
+ module Mrss
7
+
8
+ def self.patch_mongo_for_session_registry
9
+
10
+ Mongo::Client.class_eval do
11
+ alias :get_session_without_tracking :get_session
12
+
13
+ def get_session(options = {})
14
+ get_session_without_tracking(options).tap do |session|
15
+ SessionRegistry.instance.register(session) if session&.materialized?
16
+ end
17
+ end
18
+ end
19
+
20
+ Mongo::Session.class_eval do
21
+ alias :end_session_without_tracking :end_session
22
+
23
+ def end_session
24
+ SessionRegistry.instance.unregister(self)
25
+ end_session_without_tracking
26
+ end
27
+
28
+ alias :materialize_if_needed_without_tracking :materialize_if_needed
29
+
30
+ def materialize_if_needed
31
+ materialize_if_needed_without_tracking.tap do
32
+ SessionRegistry.instance.register(self)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module Mrss
40
+ class SessionRegistry
41
+ include Singleton
42
+
43
+ def initialize
44
+ @registry = {}
45
+ end
46
+
47
+ def register(session)
48
+ @registry[session.session_id] = session if session
49
+ end
50
+
51
+ def unregister(session)
52
+ return if session.ended? || !session.materialized?
53
+ @registry.delete(session.session_id)
54
+ end
55
+
56
+ def verify_sessions_ended!
57
+ @registry.delete_if { |_, session| session.ended? }
58
+
59
+ unless @registry.empty?
60
+ sessions = @registry.map { |_, session| session }
61
+ raise "Session registry contains live sessions: #{sessions.join(', ')}"
62
+ end
63
+ end
64
+
65
+ def clear_registry
66
+ @registry = {}
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'singleton'
5
+
6
+ module Mrss
7
+
8
+ def self.patch_mongo_for_session_registry
9
+
10
+ Mongo::Client.class_eval do
11
+ alias :get_session_without_tracking :get_session
12
+
13
+ def get_session(options = {})
14
+ get_session_without_tracking(options).tap do |session|
15
+ SessionRegistry.instance.register(session)
16
+ end
17
+ end
18
+ end
19
+
20
+ Mongo::Session.class_eval do
21
+ alias :end_session_without_tracking :end_session
22
+
23
+ def end_session
24
+ SessionRegistry.instance.unregister(self)
25
+ end_session_without_tracking
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ module Mrss
32
+ class SessionRegistry
33
+ include Singleton
34
+
35
+ def initialize
36
+ @registry = {}
37
+ end
38
+
39
+ def register(session)
40
+ @registry[session.session_id] = session if session
41
+ end
42
+
43
+ def unregister(session)
44
+ @registry.delete(session.session_id) unless session.ended?
45
+ end
46
+
47
+ def verify_sessions_ended!
48
+ @registry.delete_if { |_, session| session.ended? }
49
+
50
+ unless @registry.empty?
51
+ sessions = @registry.map { |_, session| session }
52
+ raise "Session registry contains live sessions: #{sessions.join(', ')}"
53
+ end
54
+ end
55
+
56
+ def clear_registry
57
+ @registry = {}
58
+ end
59
+ end
60
+ end
@@ -3,13 +3,35 @@
3
3
 
4
4
  module Mrss
5
5
  module Utils
6
+ extend self
6
7
 
7
- module_function def print_backtrace(dest=STDERR)
8
- begin
9
- hello world
10
- rescue => e
11
- dest.puts e.backtrace.join("\n")
12
- end
8
+ def print_backtrace(dest=STDERR)
9
+ raise
10
+ rescue => e
11
+ dest.puts e.backtrace.join("\n")
12
+ end
13
+
14
+ # Parses the given version string, accounting for suffix information that
15
+ # Gem::Version cannot successfully parse.
16
+ #
17
+ # @param [ String ] version the version to parse
18
+ #
19
+ # @return [ Gem::Version ] the parsed version
20
+ #
21
+ # @raise [ ArgumentError ] if the string cannot be parsed.
22
+ def parse_version(version)
23
+ Gem::Version.new(version)
24
+ rescue ArgumentError
25
+ match = version.match(/\A(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)?(-[A-Za-z\+\d]+)?\z/)
26
+ raise ArgumentError.new("Malformed version number string #{version}") if match.nil?
27
+
28
+ Gem::Version.new(
29
+ [
30
+ match[:major],
31
+ match[:minor],
32
+ match[:patch]
33
+ ].join('.')
34
+ )
13
35
  end
14
36
  end
15
37
  end