mongoid 7.2.0 → 7.3.0

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/Rakefile +16 -0
  4. data/lib/config/locales/en.yml +2 -2
  5. data/lib/mongoid/association/accessors.rb +1 -1
  6. data/lib/mongoid/association/constrainable.rb +1 -1
  7. data/lib/mongoid/association/depending.rb +4 -4
  8. data/lib/mongoid/association/embedded/batchable.rb +1 -1
  9. data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
  10. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
  11. data/lib/mongoid/association/nested/many.rb +1 -1
  12. data/lib/mongoid/association/nested/one.rb +4 -2
  13. data/lib/mongoid/association/proxy.rb +6 -1
  14. data/lib/mongoid/association/referenced/auto_save.rb +2 -2
  15. data/lib/mongoid/association/referenced/has_many/enumerable.rb +493 -495
  16. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  17. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
  18. data/lib/mongoid/attributes/projector.rb +120 -0
  19. data/lib/mongoid/attributes.rb +32 -14
  20. data/lib/mongoid/cacheable.rb +2 -2
  21. data/lib/mongoid/clients/factory.rb +22 -8
  22. data/lib/mongoid/clients.rb +1 -1
  23. data/lib/mongoid/config.rb +19 -2
  24. data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
  25. data/lib/mongoid/copyable.rb +1 -1
  26. data/lib/mongoid/criteria/findable.rb +1 -1
  27. data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
  28. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  29. data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
  30. data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
  31. data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
  32. data/lib/mongoid/criteria/queryable/selector.rb +0 -4
  33. data/lib/mongoid/criteria.rb +4 -5
  34. data/lib/mongoid/document.rb +4 -17
  35. data/lib/mongoid/errors/delete_restriction.rb +8 -9
  36. data/lib/mongoid/evolvable.rb +1 -1
  37. data/lib/mongoid/extensions/boolean.rb +1 -2
  38. data/lib/mongoid/extensions/false_class.rb +1 -1
  39. data/lib/mongoid/extensions/hash.rb +2 -2
  40. data/lib/mongoid/extensions/true_class.rb +1 -1
  41. data/lib/mongoid/fields.rb +43 -5
  42. data/lib/mongoid/inspectable.rb +1 -1
  43. data/lib/mongoid/interceptable.rb +3 -1
  44. data/lib/mongoid/matcher/bits.rb +41 -0
  45. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  46. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  47. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  48. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  49. data/lib/mongoid/matcher/elem_match.rb +2 -1
  50. data/lib/mongoid/matcher/expression.rb +9 -14
  51. data/lib/mongoid/matcher/field_expression.rb +4 -5
  52. data/lib/mongoid/matcher/field_operator.rb +13 -11
  53. data/lib/mongoid/matcher/mod.rb +17 -0
  54. data/lib/mongoid/matcher/type.rb +99 -0
  55. data/lib/mongoid/matcher.rb +26 -43
  56. data/lib/mongoid/persistable/deletable.rb +1 -2
  57. data/lib/mongoid/persistable/destroyable.rb +8 -2
  58. data/lib/mongoid/persistable/updatable.rb +27 -2
  59. data/lib/mongoid/query_cache.rb +35 -29
  60. data/lib/mongoid/reloadable.rb +5 -0
  61. data/lib/mongoid/selectable.rb +5 -7
  62. data/lib/mongoid/shardable.rb +21 -5
  63. data/lib/mongoid/touchable.rb +23 -4
  64. data/lib/mongoid/version.rb +1 -1
  65. data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
  66. data/spec/integration/app_spec.rb +171 -84
  67. data/spec/integration/associations/embeds_many_spec.rb +44 -0
  68. data/spec/integration/associations/has_one_spec.rb +48 -0
  69. data/spec/integration/callbacks_models.rb +49 -0
  70. data/spec/integration/callbacks_spec.rb +216 -0
  71. data/spec/integration/criteria/date_field_spec.rb +1 -1
  72. data/spec/integration/document_spec.rb +30 -0
  73. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  74. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  75. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  76. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  77. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  78. data/spec/integration/matcher_operator_data/elem_match.yml +46 -0
  79. data/spec/integration/matcher_operator_data/gt_types.yml +63 -0
  80. data/spec/integration/matcher_operator_data/gte_types.yml +15 -0
  81. data/spec/integration/matcher_operator_data/implicit_traversal.yml +96 -0
  82. data/spec/integration/matcher_operator_data/in.yml +16 -0
  83. data/spec/integration/matcher_operator_data/lt_types.yml +15 -0
  84. data/spec/integration/matcher_operator_data/lte_types.yml +15 -0
  85. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  86. data/spec/integration/matcher_operator_data/ne_types.yml +15 -0
  87. data/spec/integration/matcher_operator_data/type.yml +70 -0
  88. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  89. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  90. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  91. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  92. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  93. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  94. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  95. data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
  96. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  97. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  98. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  99. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  100. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  101. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  102. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  103. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  104. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  105. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  106. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  107. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  108. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  109. data/spec/lite_spec_helper.rb +5 -4
  110. data/spec/mongoid/association/depending_spec.rb +391 -352
  111. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
  112. data/spec/mongoid/association/nested/one_spec.rb +18 -14
  113. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
  114. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
  115. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
  116. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +1 -1
  117. data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
  118. data/spec/mongoid/atomic/paths_spec.rb +105 -12
  119. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  120. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  121. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  122. data/spec/mongoid/attributes_spec.rb +333 -0
  123. data/spec/mongoid/clients/factory_spec.rb +48 -0
  124. data/spec/mongoid/config_spec.rb +32 -0
  125. data/spec/mongoid/contextual/atomic_spec.rb +17 -4
  126. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  127. data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
  128. data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
  129. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
  130. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
  131. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +265 -24
  132. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  133. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
  134. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  135. data/spec/mongoid/criteria_projection_spec.rb +411 -0
  136. data/spec/mongoid/criteria_spec.rb +0 -275
  137. data/spec/mongoid/document_fields_spec.rb +26 -0
  138. data/spec/mongoid/document_spec.rb +13 -13
  139. data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
  140. data/spec/mongoid/extensions/false_class_spec.rb +1 -1
  141. data/spec/mongoid/extensions/string_spec.rb +5 -5
  142. data/spec/mongoid/extensions/true_class_spec.rb +1 -1
  143. data/spec/mongoid/fields/localized_spec.rb +4 -4
  144. data/spec/mongoid/fields_spec.rb +4 -4
  145. data/spec/mongoid/inspectable_spec.rb +12 -4
  146. data/spec/mongoid/matcher/extract_attribute_data/numeric_keys.yml +104 -0
  147. data/spec/mongoid/matcher/extract_attribute_data/traversal.yml +68 -88
  148. data/spec/mongoid/matcher/extract_attribute_spec.rb +3 -13
  149. data/spec/mongoid/persistable/deletable_spec.rb +175 -1
  150. data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
  151. data/spec/mongoid/persistable/savable_spec.rb +3 -5
  152. data/spec/mongoid/persistable/settable_spec.rb +30 -0
  153. data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
  154. data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
  155. data/spec/mongoid/reloadable_spec.rb +18 -1
  156. data/spec/mongoid/shardable_spec.rb +44 -0
  157. data/spec/mongoid/touchable_spec.rb +104 -16
  158. data/spec/mongoid/touchable_spec_models.rb +52 -0
  159. data/spec/mongoid/validatable_spec.rb +1 -1
  160. data/spec/shared/bin/get-mongodb-download-url +17 -0
  161. data/spec/shared/lib/mrss/cluster_config.rb +221 -0
  162. data/spec/shared/lib/mrss/constraints.rb +51 -0
  163. data/spec/shared/lib/mrss/docker_runner.rb +265 -0
  164. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  165. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  166. data/spec/shared/lib/mrss/spec_organizer.rb +14 -1
  167. data/spec/shared/lib/mrss/utils.rb +15 -0
  168. data/spec/shared/share/Dockerfile.erb +231 -0
  169. data/spec/shared/shlib/distro.sh +73 -0
  170. data/spec/shared/shlib/server.sh +290 -0
  171. data/spec/shared/shlib/set_env.sh +128 -0
  172. data/spec/spec_helper.rb +6 -2
  173. data/spec/support/client_registry.rb +9 -0
  174. data/spec/support/models/bolt.rb +8 -0
  175. data/spec/support/models/customer.rb +11 -0
  176. data/spec/support/models/customer_address.rb +12 -0
  177. data/spec/support/models/dictionary.rb +6 -0
  178. data/spec/support/models/hole.rb +13 -0
  179. data/spec/support/models/mop.rb +9 -0
  180. data/spec/support/models/nut.rb +8 -0
  181. data/spec/support/models/person.rb +6 -0
  182. data/spec/support/models/sealer.rb +8 -0
  183. data/spec/support/models/shirt.rb +12 -0
  184. data/spec/support/models/spacer.rb +8 -0
  185. data/spec/support/models/threadlocker.rb +8 -0
  186. data/spec/support/models/washer.rb +8 -0
  187. data/spec/support/spec_config.rb +8 -0
  188. data.tar.gz.sig +0 -0
  189. metadata +146 -14
  190. metadata.gz.sig +5 -2
  191. data/spec/support/cluster_config.rb +0 -158
@@ -2,6 +2,7 @@
2
2
  # encoding: utf-8
3
3
 
4
4
  require "spec_helper"
5
+ require_relative './touchable_spec_models'
5
6
 
6
7
  describe Mongoid::Touchable do
7
8
 
@@ -9,7 +10,7 @@ describe Mongoid::Touchable do
9
10
 
10
11
  context "when the document has no associations" do
11
12
  let(:updatable) do
12
- Updatable.create
13
+ Updatable.create!
13
14
  end
14
15
 
15
16
  it "responds to #touch" do
@@ -28,30 +29,117 @@ describe Mongoid::Touchable do
28
29
  end
29
30
  end
30
31
 
31
- context "when the document is embedded" do
32
+ context 'when the document has a parent association' do
32
33
 
33
- before do
34
- Label.send(:include, Mongoid::Touchable::InstanceMethods)
34
+ let(:building) do
35
+ parent_cls.create!
35
36
  end
36
37
 
37
- let(:band) do
38
- Band.create(name: "Placebo")
38
+ let(:entrance) do
39
+ building.entrances.create!
39
40
  end
40
41
 
41
- let(:label) do
42
- band.create_label(name: "Mute", updated_at: 10.days.ago)
42
+ let(:floor) do
43
+ building.floors.create!
43
44
  end
44
45
 
45
- before do
46
- label.touch
46
+ let!(:start_time) { Timecop.freeze(Time.at(Time.now.to_i)) }
47
+
48
+ let(:update_time) do
49
+ Timecop.freeze(Time.at(Time.now.to_i) + 2)
47
50
  end
48
51
 
49
- it "updates the updated_at timestamp" do
50
- expect(label.updated_at).to be_within(1).of(Time.now)
52
+ after do
53
+ Timecop.return
54
+ end
55
+
56
+ shared_examples 'updates the child' do
57
+ it "updates the updated_at timestamp" do
58
+ entrance
59
+ update_time
60
+ entrance.touch
61
+
62
+ entrance.updated_at.should == update_time
63
+ end
64
+
65
+ it "persists the changes" do
66
+ entrance
67
+ update_time
68
+ entrance.touch
69
+
70
+ entrance.reload.updated_at.should == update_time
71
+ end
51
72
  end
52
73
 
53
- it "persists the changes" do
54
- expect(label.reload.updated_at).to be_within(1).of(Time.now)
74
+ shared_examples 'updates the parent when :touch is true' do
75
+
76
+ it 'updates updated_at on parent' do
77
+ floor
78
+ update_time
79
+ floor.touch
80
+
81
+ building.updated_at.should == update_time
82
+ end
83
+
84
+ it 'persists updated updated_at on parent' do
85
+ floor
86
+ update_time
87
+ floor.touch
88
+
89
+ building.reload.updated_at.should == update_time
90
+ end
91
+ end
92
+
93
+ shared_examples 'updates the parent when :touch is not set' do
94
+ it 'does not update updated_at on parent' do
95
+ entrance
96
+ update_time
97
+ entrance.touch
98
+
99
+ building.updated_at.should == update_time
100
+ end
101
+
102
+ it 'does not persist updated updated_at on parent' do
103
+ entrance
104
+ update_time
105
+ entrance.touch
106
+
107
+ building.reload.updated_at.should == update_time
108
+ end
109
+ end
110
+
111
+ shared_examples 'does not update the parent when :touch is not set' do
112
+ it 'does not update updated_at on parent' do
113
+ entrance
114
+ update_time
115
+ entrance.touch
116
+
117
+ building.updated_at.should == start_time
118
+ end
119
+
120
+ it 'does not persist updated updated_at on parent' do
121
+ entrance
122
+ update_time
123
+ entrance.touch
124
+
125
+ building.reload.updated_at.should == start_time
126
+ end
127
+ end
128
+
129
+ context "when the document is embedded" do
130
+ let(:parent_cls) { TouchableSpec::Embedded::Building }
131
+
132
+ include_examples 'updates the child'
133
+ include_examples 'updates the parent when :touch is true'
134
+ include_examples 'updates the parent when :touch is not set'
135
+ end
136
+
137
+ context "when the document is referenced" do
138
+ let(:parent_cls) { TouchableSpec::Referenced::Building }
139
+
140
+ include_examples 'updates the child'
141
+ include_examples 'updates the parent when :touch is true'
142
+ include_examples 'does not update the parent when :touch is not set'
55
143
  end
56
144
  end
57
145
 
@@ -415,11 +503,11 @@ describe Mongoid::Touchable do
415
503
  context "when modifying the child" do
416
504
 
417
505
  let!(:agency) do
418
- Agency.create
506
+ Agency.create!
419
507
  end
420
508
 
421
509
  let!(:agent) do
422
- agency.agents.create(number: '1')
510
+ agency.agents.create!(number: '1')
423
511
  end
424
512
 
425
513
  it "updates the parent's updated at" do
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ module TouchableSpec
5
+ module Embedded
6
+ class Building
7
+ include Mongoid::Document
8
+ include Mongoid::Timestamps
9
+
10
+ embeds_many :entrances
11
+ embeds_many :floors
12
+ end
13
+
14
+ class Entrance
15
+ include Mongoid::Document
16
+ include Mongoid::Timestamps
17
+
18
+ embedded_in :building
19
+ end
20
+
21
+ class Floor
22
+ include Mongoid::Document
23
+ include Mongoid::Timestamps
24
+
25
+ embedded_in :building, touch: true
26
+ end
27
+ end
28
+
29
+ module Referenced
30
+ class Building
31
+ include Mongoid::Document
32
+ include Mongoid::Timestamps
33
+
34
+ has_many :entrances, inverse_of: :building
35
+ has_many :floors, inverse_of: :building
36
+ end
37
+
38
+ class Entrance
39
+ include Mongoid::Document
40
+ include Mongoid::Timestamps
41
+
42
+ belongs_to :building
43
+ end
44
+
45
+ class Floor
46
+ include Mongoid::Document
47
+ include Mongoid::Timestamps
48
+
49
+ belongs_to :building, touch: true
50
+ end
51
+ end
52
+ end
@@ -37,7 +37,7 @@ describe Mongoid::Validatable do
37
37
  end
38
38
 
39
39
  let(:documents) do
40
- Mongoid::Association::Referenced::HasMany::Targets::Enumerable.new([ address ])
40
+ Mongoid::Association::Referenced::HasMany::Enumerable.new([ address ])
41
41
  end
42
42
 
43
43
  before do
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ desired_version, arch = ARGV
4
+ if arch.nil?
5
+ STDERR.puts "Usage: get-mongodb-download-url desired-version arch"
6
+ exit 1
7
+ end
8
+
9
+ $: << File.join(File.dirname(__FILE__), '../lib')
10
+ require 'mrss/server_version_registry'
11
+
12
+ begin
13
+ puts Mrss::ServerVersionRegistry.new(desired_version, arch).download_url
14
+ rescue Mrss::ServerVersionRegistry::Error => exc
15
+ STDERR.puts "Error: #{exc}"
16
+ exit 2
17
+ end
@@ -0,0 +1,221 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ # ClusterConfig requires ClientRegistry class provided by the host project.
5
+
6
+ require 'singleton'
7
+
8
+ module Mrss
9
+ class ClusterConfig
10
+ include Singleton
11
+ include RSpec::Core::Pending
12
+
13
+ def single_server?
14
+ determine_cluster_config
15
+ @single_server
16
+ end
17
+
18
+ def replica_set_name
19
+ determine_cluster_config
20
+ @replica_set_name
21
+ end
22
+
23
+ def server_version
24
+ determine_cluster_config
25
+ @server_version
26
+ end
27
+
28
+ def enterprise?
29
+ determine_cluster_config
30
+ @enterprise
31
+ end
32
+
33
+ def short_server_version
34
+ server_version.split('.')[0..1].join('.')
35
+ end
36
+
37
+ def fcv
38
+ determine_cluster_config
39
+ @fcv
40
+ end
41
+
42
+ # Per https://jira.mongodb.org/browse/SERVER-39052, working with FCV
43
+ # in sharded topologies is annoying. Also, FCV doesn't exist in servers
44
+ # less than 3.4. This method returns FCV on 3.4+ servers when in single
45
+ # or RS topologies, and otherwise returns the major.minor server version.
46
+ def fcv_ish
47
+ if server_version.nil?
48
+ raise "Deployment server version not known - check that connection to deployment succeeded"
49
+ end
50
+
51
+ if server_version >= '3.4' && topology != :sharded
52
+ fcv
53
+ else
54
+ if short_server_version == '4.1'
55
+ '4.2'
56
+ else
57
+ short_server_version
58
+ end
59
+ end
60
+ end
61
+
62
+ # @return [ Mongo::Address ] The address of the primary in the deployment.
63
+ def primary_address
64
+ determine_cluster_config
65
+ @primary_address
66
+ end
67
+
68
+ def primary_address_str
69
+ determine_cluster_config
70
+ @primary_address.seed
71
+ end
72
+
73
+ def primary_address_host
74
+ both = primary_address_str
75
+ both.split(':').first
76
+ end
77
+
78
+ def primary_address_port
79
+ both = primary_address_str
80
+ both.split(':')[1] || 27017
81
+ end
82
+
83
+ def primary_description
84
+ determine_cluster_config
85
+ @primary_description
86
+ end
87
+
88
+ def server_parameters
89
+ determine_cluster_config
90
+ @server_parameters
91
+ end
92
+
93
+ # Try running a command on the admin database to see if the mongod was
94
+ # started with auth.
95
+ def auth_enabled?
96
+ if @auth_enabled.nil?
97
+ @auth_enabled = begin
98
+ basic_client.use(:admin).command(getCmdLineOpts: 1).first["argv"].include?("--auth")
99
+ rescue => e
100
+ e.message =~ /(not authorized)|(unauthorized)|(no users authenticated)|(requires authentication)/
101
+ end
102
+ end
103
+ @auth_enabled
104
+ end
105
+
106
+ def topology
107
+ determine_cluster_config
108
+ @topology
109
+ end
110
+
111
+ def storage_engine
112
+ @storage_engine ||= begin
113
+ # 2.6 does not have wired tiger
114
+ if short_server_version == '2.6'
115
+ :mmapv1
116
+ else
117
+ client = ClientRegistry.instance.global_client('root_authorized')
118
+ if topology == :sharded
119
+ shards = client.use(:admin).command(listShards: 1).first
120
+ if shards['shards'].empty?
121
+ raise 'Shards are empty'
122
+ end
123
+ shard = shards['shards'].first
124
+ address_str = shard['host'].sub(/^.*\//, '').sub(/,.*/, '')
125
+ client = ClusterTools.instance.direct_client(address_str,
126
+ SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options).merge(connect: :direct))
127
+ end
128
+ rv = client.use(:admin).command(serverStatus: 1).first
129
+ rv = rv['storageEngine']['name']
130
+ rv_map = {
131
+ 'wiredTiger' => :wired_tiger,
132
+ 'mmapv1' => :mmapv1,
133
+ }
134
+ rv_map[rv] || rv
135
+ end
136
+ end
137
+ end
138
+
139
+ # This method returns an alternate address for connecting to the configured
140
+ # deployment. For example, if the replica set is configured with nodes at
141
+ # of localhost:27017 and so on, this method will return 127.0.0.:27017.
142
+ #
143
+ # Note that the "alternate" refers to replica set configuration, not the
144
+ # addresses specified in test suite configuration. If the deployment topology
145
+ # is not a replica set, "alternate" refers to test suite configuration as
146
+ # this is the only configuration available.
147
+ def alternate_address
148
+ @alternate_address ||= begin
149
+ address = primary_address_host
150
+ str = case address
151
+ when '127.0.0.1'
152
+ 'localhost'
153
+ when /^(\d+\.){3}\d+$/
154
+ skip 'This test requires a hostname or 127.0.0.1 as address'
155
+ else
156
+ # We don't know if mongod is listening on ipv4 or ipv6, in principle.
157
+ # Our tests use ipv4, so hardcode that for now.
158
+ # To support both we need to try both addresses which will make this
159
+ # test more complicated.
160
+ #
161
+ # JRuby chokes on primary_address_port as the port (e.g. 27017).
162
+ # Since the port does not actually matter, use a common port like 80.
163
+ resolved_address = Addrinfo.getaddrinfo(address, 80, Socket::PF_INET).first.ip_address
164
+ if resolved_address.include?(':')
165
+ "[#{resolved_address}]"
166
+ else
167
+ resolved_address
168
+ end
169
+ end + ":#{primary_address_port}"
170
+ Mongo::Address.new(str)
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ def determine_cluster_config
177
+ return if @primary_address
178
+
179
+ # Run all commands to figure out the cluster configuration from the same
180
+ # client. This is somewhat wasteful when running a single test, but reduces
181
+ # test runtime for the suite overall because all commands are sent on the
182
+ # same connection rather than each command connecting to the cluster by
183
+ # itself.
184
+ client = ClientRegistry.instance.global_client('root_authorized')
185
+
186
+ primary = client.cluster.next_primary
187
+ @primary_address = primary.address
188
+ @primary_description = primary.description
189
+ @replica_set_name = client.cluster.topology.replica_set_name
190
+
191
+ @topology ||= begin
192
+ topology = client.cluster.topology.class.name.sub(/.*::/, '')
193
+ topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
194
+ if topology =~ /^replica_set/
195
+ topology = 'replica_set'
196
+ end
197
+ topology.to_sym
198
+ end
199
+
200
+ @single_server = client.cluster.servers_list.length == 1
201
+
202
+ build_info = client.database.command(buildInfo: 1).first
203
+
204
+ @server_version = build_info['version']
205
+ @enterprise = build_info['modules'] && build_info['modules'].include?('enterprise')
206
+
207
+ @server_parameters = client.use(:admin).command(getParameter: '*').first
208
+
209
+ if @topology != :sharded && short_server_version >= '3.4'
210
+ rv = @server_parameters['featureCompatibilityVersion']
211
+ @fcv = rv['version'] || rv
212
+ end
213
+ end
214
+
215
+ def basic_client
216
+ # Do not cache the result here so that if the client gets closed,
217
+ # client registry reconnects it in subsequent tests
218
+ ClientRegistry.instance.global_client('basic')
219
+ end
220
+ end
221
+ 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?
@@ -147,6 +155,33 @@ module Mrss
147
155
  end
148
156
  end
149
157
 
158
+ def require_no_snappy_compression
159
+ before(:all) do
160
+ compressors = SpecConfig.instance.compressors
161
+ if compressors && compressors.include?('snappy')
162
+ skip "Snappy compression is enabled"
163
+ end
164
+ end
165
+ end
166
+
167
+ def require_zstd_compression
168
+ before(:all) do
169
+ compressors = SpecConfig.instance.compressors
170
+ unless compressors && compressors.include?('zstd')
171
+ skip "Zstd compression is not enabled"
172
+ end
173
+ end
174
+ end
175
+
176
+ def require_no_zstd_compression
177
+ before(:all) do
178
+ compressors = SpecConfig.instance.compressors
179
+ if compressors && compressors.include?('zstd')
180
+ skip "Zstd compression is enabled"
181
+ end
182
+ end
183
+ end
184
+
150
185
  def require_no_compression
151
186
  before(:all) do
152
187
  if SpecConfig.instance.compressors
@@ -299,5 +334,21 @@ module Mrss
299
334
  end
300
335
  end
301
336
  end
337
+
338
+ def require_required_api_version
339
+ before(:all) do
340
+ unless ENV['API_VERSION_REQUIRED'] == '1'
341
+ skip 'Set API_VERSION_REQUIRED=1 to run this test'
342
+ end
343
+ end
344
+ end
345
+
346
+ def require_no_required_api_version
347
+ before(:all) do
348
+ if ENV['API_VERSION_REQUIRED'] == '1'
349
+ skip 'Cannot have API_VERSION_REQUIRED=1 to run this test'
350
+ end
351
+ end
352
+ end
302
353
  end
303
354
  end