mongoid 7.0.6 → 7.0.12

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 (91) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +1 -1
  5. data/Rakefile +14 -5
  6. data/lib/mongoid.rb +1 -1
  7. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  8. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  9. data/lib/mongoid/association/proxy.rb +1 -1
  10. data/lib/mongoid/atomic.rb +13 -3
  11. data/lib/mongoid/clients/sessions.rb +20 -4
  12. data/lib/mongoid/criteria.rb +7 -1
  13. data/lib/mongoid/criteria/modifiable.rb +2 -1
  14. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  15. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  16. data/lib/mongoid/criteria/queryable/extensions/time.rb +1 -1
  17. data/lib/mongoid/criteria/queryable/extensions/time_with_zone.rb +12 -0
  18. data/lib/mongoid/document.rb +3 -2
  19. data/lib/mongoid/extensions/hash.rb +4 -2
  20. data/lib/mongoid/extensions/regexp.rb +1 -1
  21. data/lib/mongoid/fields.rb +2 -1
  22. data/lib/mongoid/interceptable.rb +3 -1
  23. data/lib/mongoid/matchable/regexp.rb +2 -2
  24. data/lib/mongoid/persistable/pushable.rb +11 -2
  25. data/lib/mongoid/persistence_context.rb +6 -6
  26. data/lib/mongoid/query_cache.rb +61 -18
  27. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  28. data/lib/mongoid/version.rb +1 -1
  29. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  30. data/spec/app/models/customer.rb +11 -0
  31. data/spec/app/models/customer_address.rb +12 -0
  32. data/spec/app/models/delegating_patient.rb +16 -0
  33. data/spec/integration/app_spec.rb +192 -0
  34. data/spec/integration/associations/embedded_spec.rb +62 -0
  35. data/spec/integration/callbacks_models.rb +49 -0
  36. data/spec/integration/callbacks_spec.rb +216 -0
  37. data/spec/integration/criteria/date_field_spec.rb +41 -0
  38. data/spec/integration/document_spec.rb +22 -0
  39. data/spec/lite_spec_helper.rb +12 -4
  40. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
  41. data/spec/mongoid/association/embedded/embeds_many_models.rb +53 -0
  42. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  43. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  44. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +140 -1
  45. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +105 -0
  46. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  47. data/spec/mongoid/atomic/paths_spec.rb +41 -0
  48. data/spec/mongoid/clients/options_spec.rb +4 -4
  49. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  50. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  51. data/spec/mongoid/clients_spec.rb +2 -2
  52. data/spec/mongoid/contextual/atomic_spec.rb +20 -10
  53. data/spec/mongoid/contextual/geo_near_spec.rb +11 -2
  54. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  55. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  56. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  57. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  58. data/spec/mongoid/criteria/queryable/extensions/time_spec.rb +19 -7
  59. data/spec/mongoid/criteria/queryable/extensions/time_with_zone_spec.rb +28 -1
  60. data/spec/mongoid/criteria_spec.rb +4 -2
  61. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  62. data/spec/mongoid/indexable_spec.rb +6 -4
  63. data/spec/mongoid/matchable/default_spec.rb +1 -1
  64. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  65. data/spec/mongoid/matchable_spec.rb +2 -2
  66. data/spec/mongoid/persistable/pushable_spec.rb +55 -1
  67. data/spec/mongoid/query_cache_spec.rb +77 -9
  68. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  69. data/spec/mongoid/scopable_spec.rb +2 -1
  70. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  71. data/spec/mongoid/tasks/database_spec.rb +1 -1
  72. data/spec/shared/LICENSE +20 -0
  73. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  74. data/spec/shared/lib/mrss/cluster_config.rb +211 -0
  75. data/spec/shared/lib/mrss/constraints.rb +330 -0
  76. data/spec/shared/lib/mrss/docker_runner.rb +262 -0
  77. data/spec/shared/lib/mrss/lite_constraints.rb +175 -0
  78. data/spec/shared/lib/mrss/server_version_registry.rb +69 -0
  79. data/spec/shared/lib/mrss/spec_organizer.rb +149 -0
  80. data/spec/shared/share/Dockerfile.erb +229 -0
  81. data/spec/shared/shlib/distro.sh +73 -0
  82. data/spec/shared/shlib/server.sh +270 -0
  83. data/spec/shared/shlib/set_env.sh +128 -0
  84. data/spec/spec_helper.rb +0 -31
  85. data/spec/support/child_process_helper.rb +76 -0
  86. data/spec/support/cluster_config.rb +3 -3
  87. data/spec/support/constraints.rb +201 -30
  88. data/spec/support/session_registry.rb +50 -0
  89. data/spec/support/spec_config.rb +12 -4
  90. metadata +510 -461
  91. metadata.gz.sig +2 -2
data/spec/spec_helper.rb CHANGED
@@ -75,37 +75,6 @@ CONFIG = {
75
75
  }
76
76
  }
77
77
 
78
- def non_legacy_server?
79
- Mongoid::Clients.default.cluster.servers.first.features.write_command_enabled?
80
- end
81
-
82
- def testing_replica_set?
83
- Mongoid::Clients.default.cluster.replica_set?
84
- end
85
-
86
- def collation_supported?
87
- Mongoid::Clients.default.cluster.next_primary.features.collation_enabled?
88
- end
89
- alias :decimal128_supported? :collation_supported?
90
-
91
- def array_filters_supported?
92
- Mongoid::Clients.default.cluster.next_primary.features.array_filters_enabled?
93
- end
94
- alias :sessions_supported? :array_filters_supported?
95
-
96
- def transactions_supported?
97
- features = Mongoid::Clients.default.cluster.next_primary.features
98
- features.respond_to?(:transactions_enabled?) && features.transactions_enabled?
99
- end
100
-
101
- def testing_transactions?
102
- transactions_supported? && testing_replica_set?
103
- end
104
-
105
- def testing_locally?
106
- !(ENV['CI'] == 'travis')
107
- end
108
-
109
78
  # Set the database that the spec suite connects to.
110
79
  Mongoid.configure do |config|
111
80
  config.load_configuration(CONFIG)
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ autoload :ChildProcess, 'childprocess'
5
+ autoload :Tempfile, 'tempfile'
6
+
7
+ module ChildProcessHelper
8
+ module_function def call(cmd, env: nil, cwd: nil)
9
+ process = ChildProcess.new(*cmd)
10
+ process.io.inherit!
11
+ if cwd
12
+ process.cwd = cwd
13
+ end
14
+ if env
15
+ env.each do |k, v|
16
+ process.environment[k.to_s] = v
17
+ end
18
+ end
19
+ process.start
20
+ process.wait
21
+ process
22
+ end
23
+
24
+ module_function def check_call(cmd, env: nil, cwd: nil)
25
+ process = call(cmd, env: env, cwd: cwd)
26
+ unless process.exit_code == 0
27
+ raise "Failed to execute: #{cmd}"
28
+ end
29
+ end
30
+
31
+ module_function def get_output(cmd, env: nil, cwd: nil)
32
+ process = ChildProcess.new(*cmd)
33
+ process.io.inherit!
34
+ if cwd
35
+ process.cwd = cwd
36
+ end
37
+ if env
38
+ env.each do |k, v|
39
+ process.environment[k.to_s] = v
40
+ end
41
+ end
42
+
43
+ output = ''
44
+ r, w = IO.pipe
45
+
46
+ begin
47
+ process.io.stdout = w
48
+ process.start
49
+ w.close
50
+
51
+ thread = Thread.new do
52
+ begin
53
+ loop do
54
+ output << r.readpartial(16384)
55
+ end
56
+ rescue EOFError
57
+ end
58
+ end
59
+
60
+ process.wait
61
+ thread.join
62
+ ensure
63
+ r.close
64
+ end
65
+
66
+ [process, output]
67
+ end
68
+
69
+ module_function def check_output(*args)
70
+ process, output = get_output(*args)
71
+ unless process.exit_code == 0
72
+ raise "Failed to execute: #{args}"
73
+ end
74
+ output
75
+ end
76
+ end
@@ -99,7 +99,7 @@ class ClusterConfig
99
99
  if topology == :sharded
100
100
  shards = client.use(:admin).command(listShards: 1).first
101
101
  shard = shards['shards'].first
102
- address_str = shard['host'].sub(/^.*\//, '').sub(/,.*/, '')
102
+ address_str = shard['host'].sub(/\A.*\//, '').sub(/,.*/, '')
103
103
  client = ClusterTools.instance.direct_client(address_str,
104
104
  SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options).merge(connect: :direct))
105
105
  end
@@ -133,8 +133,8 @@ class ClusterConfig
133
133
 
134
134
  @topology ||= begin
135
135
  topology = client.cluster.topology.class.name.sub(/.*::/, '')
136
- topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
137
- if topology =~ /^replica_set/
136
+ topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/\A_/, '')
137
+ if topology =~ /\Areplica_set/
138
138
  topology = 'replica_set'
139
139
  end
140
140
  topology.to_sym
@@ -1,12 +1,31 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
1
4
  module Constraints
2
5
  RAILS_VERSION = ActiveSupport.version.to_s.split('.')[0..1].join('.').freeze
3
6
 
7
+ def require_driver_query_cache
8
+ before(:all) do
9
+ if !defined?(Mongo::QueryCache)
10
+ skip "Driver version #{Mongo::VERSION} does not support query cache"
11
+ end
12
+ end
13
+ end
14
+
15
+ def require_mongoid_query_cache
16
+ before (:all) do
17
+ if defined?(Mongo::QueryCache)
18
+ skip "Mongoid uses the driver query cache in driver versions that support it"
19
+ end
20
+ end
21
+ end
22
+
4
23
  def min_rails_version(version)
5
- unless version =~ /^\d+\.\d+$/
24
+ unless version =~ /\A\d+\.\d+\z/
6
25
  raise ArgumentError, "Version can only be major.minor: #{version}"
7
26
  end
8
27
 
9
- before do
28
+ before(:all) do
10
29
  if version > RAILS_VERSION
11
30
  skip "Rails version #{version} or higher required, we have #{RAILS_VERSION}"
12
31
  end
@@ -14,11 +33,11 @@ module Constraints
14
33
  end
15
34
 
16
35
  def max_rails_version(version)
17
- unless version =~ /^\d+\.\d+$/
36
+ unless version =~ /\A\d+\.\d+\z/
18
37
  raise ArgumentError, "Version can only be major.minor: #{version}"
19
38
  end
20
39
 
21
- before do
40
+ before(:all) do
22
41
  if version < RAILS_VERSION
23
42
  skip "Rails version #{version} or lower required, we have #{RAILS_VERSION}"
24
43
  end
@@ -26,11 +45,11 @@ module Constraints
26
45
  end
27
46
 
28
47
  def min_server_version(version)
29
- unless version =~ /^\d+\.\d+$/
48
+ unless version =~ /\A\d+\.\d+\z/
30
49
  raise ArgumentError, "Version can only be major.minor: #{version}"
31
50
  end
32
51
 
33
- before do
52
+ before(:all) do
34
53
  if version > ClusterConfig.instance.server_version
35
54
  skip "Server version #{version} or higher required, we have #{ClusterConfig.instance.server_version}"
36
55
  end
@@ -38,11 +57,11 @@ module Constraints
38
57
  end
39
58
 
40
59
  def max_server_version(version)
41
- unless version =~ /^\d+\.\d+$/
60
+ unless version =~ /\A\d+\.\d+\z/
42
61
  raise ArgumentError, "Version can only be major.minor: #{version}"
43
62
  end
44
63
 
45
- before do
64
+ before(:all) do
46
65
  if version < ClusterConfig.instance.short_server_version
47
66
  skip "Server version #{version} or lower required, we have #{ClusterConfig.instance.server_version}"
48
67
  end
@@ -50,18 +69,14 @@ module Constraints
50
69
  end
51
70
 
52
71
  def require_topology(*topologies)
53
- topologies = topologies.map { |t| t.to_s }
54
- invalid_topologies = topologies - %w(single replica_set sharded)
72
+ invalid_topologies = topologies - [:single, :replica_set, :sharded]
73
+
55
74
  unless invalid_topologies.empty?
56
75
  raise ArgumentError, "Invalid topologies requested: #{invalid_topologies.join(', ')}"
57
76
  end
58
- before do
59
- topology = Mongoid.default_client.cluster.topology.class.name.sub(/.*::/, '')
60
- topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
61
- if topology =~ /^replica_set/
62
- topology = 'replica_set'
63
- end
64
- unless topologies.include?(topology)
77
+
78
+ before(:all) do
79
+ unless topologies.include?(topology = ClusterConfig.instance.topology)
65
80
  skip "Topology #{topologies.join(' or ')} required, we have #{topology}"
66
81
  end
67
82
  end
@@ -69,32 +84,188 @@ module Constraints
69
84
 
70
85
  def max_example_run_time(timeout)
71
86
  around do |example|
72
- TimeoutInterrupt.timeout(timeout) do
87
+ TimeoutInterrupt.timeout(timeout, TimeoutInterrupt::Error.new("Test execution terminated after #{timeout} seconds")) do
73
88
  example.run
74
89
  end
75
90
  end
76
91
  end
77
92
 
78
93
  def require_transaction_support
79
- min_server_version '4.0'
80
- require_topology :replica_set
94
+ before(:all) do
95
+ case ClusterConfig.instance.topology
96
+ when :single
97
+ skip 'Transactions tests require a replica set (4.0+) or a sharded cluster (4.2+)'
98
+ when :replica_set
99
+ unless ClusterConfig.instance.server_version >= '4.0'
100
+ skip 'Transactions tests in a replica set topology require server 4.0+'
101
+ end
102
+ when :sharded
103
+ unless ClusterConfig.instance.server_version >= '4.2'
104
+ skip 'Transactions tests in a sharded cluster topology require server 4.2+'
105
+ end
106
+ else
107
+ raise NotImplementedError
108
+ end
109
+ end
81
110
  end
82
111
 
83
- def require_scram_sha_256_support
84
- before do
85
- $mongo_server_features ||= begin
86
- scanned_client_server!.features
112
+ def require_tls
113
+ before(:all) do
114
+ unless SpecConfig.instance.ssl?
115
+ skip "SSL not enabled"
87
116
  end
88
- unless $mongo_server_features.scram_sha_256_enabled?
89
- skip "SCRAM SHA 256 is not enabled on the server"
117
+ end
118
+ end
119
+
120
+ def require_no_tls
121
+ before(:all) do
122
+ if SpecConfig.instance.ssl?
123
+ skip "SSL enabled"
90
124
  end
91
125
  end
92
126
  end
93
127
 
94
- def require_ssl
95
- before do
96
- unless SpecConfig.instance.ssl?
97
- skip "SSL not enabled"
128
+ def require_local_tls
129
+ require_tls
130
+ end
131
+
132
+ def require_no_retry_writes
133
+ before(:all) do
134
+ if SpecConfig.instance.retry_writes?
135
+ skip "Retry writes is enabled"
136
+ end
137
+ end
138
+ end
139
+
140
+ def require_compression
141
+ before(:all) do
142
+ if SpecConfig.instance.compressors.nil?
143
+ skip "Compression is not enabled"
144
+ end
145
+ end
146
+ end
147
+
148
+ def require_no_compression
149
+ before(:all) do
150
+ if SpecConfig.instance.compressors
151
+ skip "Compression is enabled"
152
+ end
153
+ end
154
+ end
155
+
156
+ def ruby_version_gte(version)
157
+ before(:all) do
158
+ if RUBY_VERSION < version
159
+ skip "Ruby version #{version} or higher required"
160
+ end
161
+ end
162
+ end
163
+
164
+ def ruby_version_lt(version)
165
+ before(:all) do
166
+ if RUBY_VERSION >= version
167
+ skip "Ruby version less than #{version} required"
168
+ end
169
+ end
170
+ end
171
+
172
+ def require_auth
173
+ before(:all) do
174
+ unless ENV['AUTH'] == 'auth' || SpecConfig.instance.user || ClusterConfig.instance.auth_enabled?
175
+ skip "Auth required"
176
+ end
177
+ end
178
+ end
179
+
180
+ def require_no_auth
181
+ before(:all) do
182
+ if ENV['AUTH'] == 'auth' || SpecConfig.instance.user || ClusterConfig.instance.auth_enabled?
183
+ skip "Auth not allowed"
184
+ end
185
+ end
186
+ end
187
+
188
+ def require_no_x509_auth
189
+ before(:all) do
190
+ if SpecConfig.instance.x509_auth?
191
+ skip "X.509 auth not allowed"
192
+ end
193
+ end
194
+ end
195
+
196
+ # Can the driver specify a write concern that won't be overridden?
197
+ # (mongos 4.0+ overrides the write concern)
198
+ def require_set_write_concern
199
+ before(:all) do
200
+ if ClusterConfig.instance.topology == :sharded && ClusterConfig.instance.short_server_version >= '4.0'
201
+ skip "mongos 4.0+ overrides write concern"
202
+ end
203
+ end
204
+ end
205
+
206
+ def require_multi_shard
207
+ before(:all) do
208
+ if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length == 1
209
+ skip 'Test requires a minimum of two shards if run in sharded topology'
210
+ end
211
+ end
212
+ end
213
+
214
+ def require_no_multi_shard
215
+ before(:all) do
216
+ if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length > 1
217
+ skip 'Test requires a single shard if run in sharded topology'
218
+ end
219
+ end
220
+ end
221
+
222
+ def require_wired_tiger
223
+ before(:all) do
224
+ if ClusterConfig.instance.storage_engine != :wired_tiger
225
+ skip 'Test requires WiredTiger storage engine'
226
+ end
227
+ end
228
+ end
229
+
230
+ def require_wired_tiger_on_36
231
+ before(:all) do
232
+ if ClusterConfig.instance.short_server_version >= '3.6'
233
+ if ClusterConfig.instance.storage_engine != :wired_tiger
234
+ skip 'Test requires WiredTiger storage engine on 3.6+ servers'
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ def require_mmapv1
241
+ before(:all) do
242
+ if ClusterConfig.instance.storage_engine != :mmapv1
243
+ skip 'Test requires MMAPv1 storage engine'
244
+ end
245
+ end
246
+ end
247
+
248
+ def require_enterprise
249
+ before(:all) do
250
+ unless ClusterConfig.instance.enterprise?
251
+ skip 'Test requires enterprise build of MongoDB'
252
+ end
253
+ end
254
+ end
255
+
256
+ # Integration tests for SRV polling require internet connectivity to
257
+ # look up SRV records and a sharded cluster configured on default port on
258
+ # localhost (localhost:27017, localhost:27018).
259
+ def require_default_port_deployment
260
+ # Because the DNS records at test1.test.build.10gen.cc point to
261
+ # localhost:27017 & localhost:27018, the test suite must have been
262
+ # configured to use these addresses
263
+ before(:all) do
264
+ have_default_port = SpecConfig.instance.addresses.any? do |address|
265
+ %w(127.0.0.1 127.0.0.1:27017 localhost localhost:27017).include?(address)
266
+ end
267
+ unless have_default_port
268
+ skip 'This test requires the test suite to be configured for localhost:27017'
98
269
  end
99
270
  end
100
271
  end
@@ -0,0 +1,50 @@
1
+ require 'singleton'
2
+
3
+ module Mongo
4
+ class Client
5
+ alias :get_session_without_tracking :get_session
6
+
7
+ def get_session(options = {})
8
+ get_session_without_tracking(options).tap do |session|
9
+ SessionRegistry.instance.register(session)
10
+ end
11
+ end
12
+ end
13
+
14
+ class Session
15
+ alias :end_session_without_tracking :end_session
16
+
17
+ def end_session
18
+ SessionRegistry.instance.unregister(self)
19
+ end_session_without_tracking
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+ class SessionRegistry
26
+ include Singleton
27
+
28
+ def initialize
29
+ @registry = {}
30
+ end
31
+
32
+ def register(session)
33
+ @registry[session.session_id] = session if session
34
+ end
35
+
36
+ def unregister(session)
37
+ @registry.delete(session.session_id)
38
+ end
39
+
40
+ def verify_sessions_ended!
41
+ unless @registry.empty?
42
+ sessions = @registry.map { |_, session| session }
43
+ raise "Session registry contains live sessions: #{sessions.join(', ')}"
44
+ end
45
+ end
46
+
47
+ def clear_registry
48
+ @registry = {}
49
+ end
50
+ end