mongoid 7.1.1 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongoid/association/embedded/embeds_many.rb +2 -1
  5. data/lib/mongoid/association/embedded/embeds_one.rb +2 -1
  6. data/lib/mongoid/association/proxy.rb +1 -1
  7. data/lib/mongoid/atomic.rb +13 -3
  8. data/lib/mongoid/criteria.rb +7 -1
  9. data/lib/mongoid/criteria/modifiable.rb +2 -1
  10. data/lib/mongoid/criteria/queryable/extensions/numeric.rb +1 -1
  11. data/lib/mongoid/criteria/queryable/extensions/regexp.rb +3 -3
  12. data/lib/mongoid/criteria/queryable/mergeable.rb +75 -8
  13. data/lib/mongoid/criteria/queryable/selectable.rb +28 -8
  14. data/lib/mongoid/extensions/hash.rb +4 -2
  15. data/lib/mongoid/extensions/regexp.rb +1 -1
  16. data/lib/mongoid/fields.rb +2 -1
  17. data/lib/mongoid/matchable/regexp.rb +2 -2
  18. data/lib/mongoid/persistable/pushable.rb +4 -1
  19. data/lib/mongoid/persistence_context.rb +6 -6
  20. data/lib/mongoid/query_cache.rb +2 -1
  21. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  22. data/lib/mongoid/version.rb +1 -1
  23. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +1 -1
  24. data/spec/integration/app_spec.rb +192 -0
  25. data/spec/integration/associations/embedded_spec.rb +54 -0
  26. data/spec/integration/criteria/logical_spec.rb +13 -0
  27. data/spec/lite_spec_helper.rb +11 -4
  28. data/spec/mongoid/association/embedded/embeds_many_models.rb +19 -0
  29. data/spec/mongoid/association/embedded/embeds_many_spec.rb +10 -0
  30. data/spec/mongoid/association/embedded/embeds_one_spec.rb +0 -2
  31. data/spec/mongoid/association/referenced/has_and_belongs_to_many/proxy_spec.rb +2 -1
  32. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +2 -1
  33. data/spec/mongoid/clients/options_spec.rb +2 -2
  34. data/spec/mongoid/clients/sessions_spec.rb +8 -4
  35. data/spec/mongoid/clients/transactions_spec.rb +20 -8
  36. data/spec/mongoid/clients_spec.rb +2 -2
  37. data/spec/mongoid/contextual/atomic_spec.rb +22 -11
  38. data/spec/mongoid/contextual/map_reduce_spec.rb +20 -5
  39. data/spec/mongoid/contextual/mongo_spec.rb +76 -53
  40. data/spec/mongoid/criteria/queryable/extensions/regexp_spec.rb +7 -7
  41. data/spec/mongoid/criteria/queryable/extensions/string_spec.rb +1 -1
  42. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +45 -12
  43. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +480 -198
  44. data/spec/mongoid/criteria_spec.rb +4 -2
  45. data/spec/mongoid/document_persistence_context_spec.rb +33 -0
  46. data/spec/mongoid/indexable_spec.rb +6 -4
  47. data/spec/mongoid/matchable/default_spec.rb +1 -1
  48. data/spec/mongoid/matchable/regexp_spec.rb +2 -2
  49. data/spec/mongoid/matchable_spec.rb +2 -2
  50. data/spec/mongoid/query_cache_spec.rb +2 -1
  51. data/spec/mongoid/relations/proxy_spec.rb +1 -1
  52. data/spec/mongoid/scopable_spec.rb +2 -1
  53. data/spec/mongoid/shardable_models.rb +1 -1
  54. data/spec/mongoid/shardable_spec.rb +2 -2
  55. data/spec/mongoid/tasks/database_rake_spec.rb +13 -13
  56. data/spec/mongoid/tasks/database_spec.rb +1 -1
  57. data/spec/spec_helper.rb +0 -31
  58. data/spec/support/child_process_helper.rb +76 -0
  59. data/spec/support/cluster_config.rb +3 -3
  60. data/spec/support/constraints.rb +26 -10
  61. data/spec/support/spec_config.rb +12 -4
  62. metadata +8 -2
  63. metadata.gz.sig +0 -0
@@ -0,0 +1,192 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ require 'spec_helper'
5
+
6
+ BASE = File.join(File.dirname(__FILE__), '../..')
7
+ TMP_BASE = File.join(BASE, 'tmp')
8
+
9
+ describe 'Mongoid application tests' do
10
+ before(:all) do
11
+ unless SpecConfig.instance.app_tests?
12
+ skip 'Set APP_TESTS=1 in environment to run application tests'
13
+ end
14
+
15
+ require 'fileutils'
16
+ require 'support/child_process_helper'
17
+ require 'open-uri'
18
+
19
+ FileUtils.mkdir_p(TMP_BASE)
20
+ end
21
+
22
+ context 'demo application - sinatra' do
23
+ it 'runs' do
24
+ clone_application(
25
+ 'https://github.com/mongoid/mongoid-demo',
26
+ subdir: 'sinatra-minimal',
27
+ ) do
28
+
29
+ process = ChildProcess.build(*%w(bundle exec ruby app.rb))
30
+ process.environment.update(clean_env)
31
+ process.io.inherit!
32
+ process.start
33
+
34
+ begin
35
+ # JRuby needs a long timeout
36
+ wait_for_port(4567, 20)
37
+ sleep 1
38
+
39
+ uri = URI.parse('http://localhost:4567/posts')
40
+ resp = JSON.parse(uri.open.read)
41
+ ensure
42
+ Process.kill('TERM', process.pid)
43
+ status = process.wait
44
+ end
45
+
46
+ resp.should == []
47
+
48
+ status.should == 0
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'demo application - rails-api' do
54
+ ['~> 6.0.0'].each do |rails_version|
55
+ context "with rails #{rails_version}" do
56
+ it 'runs' do
57
+ clone_application(
58
+ 'https://github.com/mongoid/mongoid-demo',
59
+ subdir: 'rails-api',
60
+ rails_version: rails_version,
61
+ ) do
62
+
63
+ process = ChildProcess.build(*%w(bundle exec rails s))
64
+ process.environment.update(clean_env)
65
+ process.io.inherit!
66
+ process.start
67
+
68
+ begin
69
+ # JRuby needs a long timeout
70
+ wait_for_port(3000, 30)
71
+ sleep 1
72
+
73
+ uri = URI.parse('http://localhost:3000/posts')
74
+ resp = JSON.parse(uri.open.read)
75
+ ensure
76
+ Process.kill('TERM', process.pid)
77
+ status = process.wait
78
+ end
79
+
80
+ resp.should == []
81
+
82
+ # 143 = 128 + 15
83
+ [0, 15, 143].should include(status)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'new application - rails' do
91
+ ['~> 5.1.0', '~> 5.2.0', '~> 6.0.0'].each do |rails_version|
92
+ context "with rails #{rails_version}" do
93
+ it 'creates' do
94
+ ChildProcessHelper.check_call(%w(gem uni rails -a))
95
+ ChildProcessHelper.check_call(%w(gem install rails --no-document -v) + [rails_version])
96
+
97
+ Dir.chdir(TMP_BASE) do
98
+ FileUtils.rm_rf('mongoid-test')
99
+ ChildProcessHelper.check_call(%w(rails new mongoid-test --skip-spring), env: clean_env)
100
+
101
+ Dir.chdir('mongoid-test') do
102
+ adjust_app_gemfile
103
+ ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
104
+
105
+ ChildProcessHelper.check_call(%w(rails g model post), env: clean_env)
106
+ ChildProcessHelper.check_call(%w(rails g model comment post:belongs_to), env: clean_env)
107
+
108
+ # https://jira.mongodb.org/browse/MONGOID-4885
109
+ comment_text = File.read('app/models/comment.rb')
110
+ comment_text.should =~ /belongs_to :post/
111
+ comment_text.should_not =~ /embedded_in :post/
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ def clone_application(repo_url, subdir: nil, rails_version: nil)
120
+ Dir.chdir(TMP_BASE) do
121
+ FileUtils.rm_rf(File.basename(repo_url))
122
+ ChildProcessHelper.check_call(%w(git clone) + [repo_url])
123
+ Dir.chdir(File.join(*[File.basename(repo_url), subdir].compact)) do
124
+ adjust_app_gemfile(rails_version: rails_version)
125
+ ChildProcessHelper.check_call(%w(bundle install), env: clean_env)
126
+ puts `git diff`
127
+
128
+ config = {'development' => {'clients' => {'default' => {'uri' => SpecConfig.instance.uri_str}}}}
129
+ File.open('config/mongoid.yml', 'w') do |f|
130
+ f << YAML.dump(config)
131
+ end
132
+
133
+ yield
134
+ end
135
+ end
136
+ end
137
+
138
+ def adjust_app_gemfile(rails_version: nil)
139
+ lock_lines = IO.readlines('Gemfile.lock')
140
+ # Get rid of the bundled with line so that whatever bundler is installed
141
+ # on the system is usable with the application.
142
+ if i = lock_lines.index("BUNDLED WITH\n")
143
+ lock_lines.slice!(i, 2)
144
+ File.open('Gemfile.lock', 'w') do |f|
145
+ f << lock_lines.join
146
+ end
147
+ end
148
+
149
+ gemfile_lines = IO.readlines('Gemfile')
150
+ gemfile_lines.delete_if do |line|
151
+ line =~ /mongoid/
152
+ end
153
+ gemfile_lines << "gem 'mongoid', path: '#{File.expand_path(BASE)}'\n"
154
+ if rails_version
155
+ gemfile_lines.delete_if do |line|
156
+ line =~ /rails/
157
+ end
158
+ gemfile_lines << "gem 'rails', '#{rails_version}'\n"
159
+ end
160
+ File.open('Gemfile', 'w') do |f|
161
+ f << gemfile_lines.join
162
+ end
163
+ end
164
+
165
+ def remove_spring
166
+ # Spring produces this error in Evergreen:
167
+ # /data/mci/280eb2ecf4fd69208e2106cd3af526f1/src/rubies/ruby-2.7.0/lib/ruby/gems/2.7.0/gems/spring-2.1.0/lib/spring/client/run.rb:26:
168
+ # in `initialize': too long unix socket path (126bytes given but 108bytes max) (ArgumentError)
169
+ # Is it trying to create unix sockets in current directory?
170
+ # https://stackoverflow.com/questions/30302021/rails-runner-without-spring
171
+ ChildProcessHelper.check_call(%w(bin/spring binstub --remove --all), env: clean_env)
172
+ end
173
+
174
+ def clean_env
175
+ @clean_env ||= Hash[ENV.keys.grep(/BUNDLE|RUBYOPT/).map { |k| [k, nil ] }]
176
+ end
177
+
178
+ def wait_for_port(port, timeout)
179
+ deadline = Time.now + timeout
180
+ loop do
181
+ begin
182
+ Socket.tcp('localhost', port, nil, nil, connect_timeout: 0.5) do |socket|
183
+ return
184
+ end
185
+ rescue IOError, SystemCallError
186
+ if Time.now > deadline
187
+ raise
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'spec_helper'
5
5
  require_relative '../../mongoid/association/embedded/embeds_many_models'
6
+ require_relative '../../mongoid/association/embedded/embeds_one_models'
6
7
 
7
8
  describe 'embedded associations' do
8
9
  context 'without default order' do
@@ -118,4 +119,57 @@ describe 'embedded associations' do
118
119
  it_behaves_like 'an embedded association'
119
120
  end
120
121
  end
122
+
123
+ describe 'parent association' do
124
+ let(:parent) do
125
+ parent_cls.new
126
+ end
127
+
128
+ context 'embeds_one' do
129
+
130
+ shared_examples 'is set' do
131
+ it 'is set' do
132
+ parent.child = child_cls.new
133
+ parent.child.parent.should == parent
134
+ end
135
+ end
136
+
137
+ context 'class_name set without leading ::' do
138
+ let(:parent_cls) { EomParent }
139
+ let(:child_cls) { EomChild }
140
+
141
+ it_behaves_like 'is set'
142
+ end
143
+
144
+ context 'class_name set with leading ::' do
145
+ let(:parent_cls) { EomCcParent }
146
+ let(:child_cls) { EomCcChild }
147
+
148
+ it_behaves_like 'is set'
149
+ end
150
+ end
151
+
152
+ context 'embeds_many' do
153
+
154
+ let(:child) { parent.legislators.new }
155
+
156
+ shared_examples 'is set' do
157
+ it 'is set' do
158
+ child.congress.should == parent
159
+ end
160
+ end
161
+
162
+ context 'class_name set without leading ::' do
163
+ let(:parent_cls) { EmmCongress }
164
+
165
+ it_behaves_like 'is set'
166
+ end
167
+
168
+ context 'class_name set with leading ::' do
169
+ let(:parent_cls) { EmmCcCongress }
170
+
171
+ it_behaves_like 'is set'
172
+ end
173
+ end
174
+ end
121
175
  end
@@ -47,6 +47,19 @@ describe 'Criteria logical operations' do
47
47
  bands = Band.where(name: /jecti/).or(Band.where(name: /ush/))
48
48
  expect(bands.order_by(name: 1).to_a).to eq([ap, im])
49
49
  end
50
+
51
+ context 'when using a symbol operator' do
52
+ context 'when field has a serializer' do
53
+ let!(:doc) { Dokument.create! }
54
+
55
+ it 'works' do
56
+ scope = Dokument.or(:created_at.lte => DateTime.now).sort(id: 1)
57
+ # input was converted from DateTime to Time
58
+ scope.criteria.selector['$or'].first['created_at']['$lte'].should be_a(Time)
59
+ scope.to_a.should == [doc]
60
+ end
61
+ end
62
+ end
50
63
  end
51
64
 
52
65
  describe 'not' do
@@ -50,11 +50,18 @@ RSpec.configure do |config|
50
50
  end
51
51
 
52
52
  if SpecConfig.instance.ci?
53
- # Allow a max of 30 seconds per test.
54
- # Tests should take under 10 seconds ideally but it seems
55
- # we have some that run for more than 10 seconds in CI.
53
+ timeout = if SpecConfig.instance.app_tests?
54
+ # Allow 5 minutes per test for the app tests, since they install
55
+ # gems for Rails applications which can take a long time.
56
+ 300
57
+ else
58
+ # Allow a max of 30 seconds per test.
59
+ # Tests should take under 10 seconds ideally but it seems
60
+ # we have some that run for more than 10 seconds in CI.
61
+ 30
62
+ end
56
63
  config.around(:each) do |example|
57
- TimeoutInterrupt.timeout(30) do
64
+ TimeoutInterrupt.timeout(timeout) do
58
65
  example.run
59
66
  end
60
67
  end
@@ -18,6 +18,25 @@ class EmmLegislator
18
18
  field :b, type: Integer, default: 0
19
19
  end
20
20
 
21
+ # Models with associations with :class_name as a :: prefixed string
22
+
23
+ class EmmCcCongress
24
+ include Mongoid::Document
25
+
26
+ embeds_many :legislators, class_name: '::EmmCcLegislator'
27
+
28
+ field :name, type: String
29
+ end
30
+
31
+ class EmmCcLegislator
32
+ include Mongoid::Document
33
+
34
+ embedded_in :congress, class_name: '::EmmCcCongress'
35
+
36
+ field :a, type: Integer, default: 0
37
+ field :b, type: Integer, default: 0
38
+ end
39
+
21
40
  class EmmManufactory
22
41
  include Mongoid::Document
23
42
 
@@ -649,6 +649,16 @@ describe Mongoid::Association::Embedded::EmbedsMany do
649
649
  it 'returns the class name option' do
650
650
  expect(association.klass).to eq(_class)
651
651
  end
652
+
653
+ context 'when the class name is prefixed with ::' do
654
+ let(:options) do
655
+ { class_name: '::OtherEmbeddedObject' }
656
+ end
657
+
658
+ it 'returns the class name option' do
659
+ expect(association.klass).to eq(_class)
660
+ end
661
+ end
652
662
  end
653
663
 
654
664
  context 'when the class_name option is not specified' do
@@ -456,8 +456,6 @@ describe Mongoid::Association::Embedded::EmbedsOne do
456
456
  end
457
457
 
458
458
  it 'returns the inverse in an array' do
459
- pending 'MONGOID-4751'
460
-
461
459
  inverses = association.inverses
462
460
  expect(inverses).to eq([:parent])
463
461
  end
@@ -2689,7 +2689,8 @@ describe Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy do
2689
2689
  expect(preferences).to eq([ preference_one ])
2690
2690
  end
2691
2691
 
2692
- context 'when providing a collation', if: collation_supported? do
2692
+ context 'when providing a collation' do
2693
+ min_server_version '3.4'
2693
2694
 
2694
2695
  let(:preferences) do
2695
2696
  person.preferences.where(name: "FIRST").collation(locale: 'en_US', strength: 2).to_a
@@ -2907,7 +2907,8 @@ describe Mongoid::Association::Referenced::HasMany::Proxy do
2907
2907
  expect(posts).to eq([ post_one ])
2908
2908
  end
2909
2909
 
2910
- context 'when providing a collation', if: collation_supported? do
2910
+ context 'when providing a collation' do
2911
+ min_server_version '3.4'
2911
2912
 
2912
2913
  let(:posts) do
2913
2914
  person.posts.where(title: "FIRST").collation(locale: 'en_US', strength: 2)
@@ -14,7 +14,7 @@ describe Mongoid::Clients::Options, retry: 3 do
14
14
  Mongoid::Clients.clients.clear
15
15
  end
16
16
 
17
- describe '#with', if: non_legacy_server? do
17
+ describe '#with' do
18
18
 
19
19
  context 'when passing some options' do
20
20
 
@@ -291,7 +291,7 @@ describe Mongoid::Clients::Options, retry: 3 do
291
291
  end
292
292
  end
293
293
 
294
- describe '.with', if: non_legacy_server? do
294
+ describe '.with' do
295
295
 
296
296
  context 'when passing some options' do
297
297
 
@@ -43,7 +43,8 @@ describe Mongoid::Clients::Sessions do
43
43
 
44
44
  context 'when a session is used on a model class' do
45
45
 
46
- context 'when sessions are supported', if: sessions_supported? do
46
+ context 'when sessions are supported' do
47
+ min_server_version '3.6'
47
48
 
48
49
  around do |example|
49
50
  Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
@@ -172,7 +173,8 @@ describe Mongoid::Clients::Sessions do
172
173
  end
173
174
  end
174
175
 
175
- context 'when sessions are not supported', unless: sessions_supported? do
176
+ context 'when sessions are not supported' do
177
+ max_server_version '3.4'
176
178
 
177
179
  let!(:error) do
178
180
  e = nil
@@ -199,7 +201,8 @@ describe Mongoid::Clients::Sessions do
199
201
  end
200
202
  end
201
203
 
202
- context 'when sessions are supported', if: sessions_supported? do
204
+ context 'when sessions are supported' do
205
+ min_server_version '3.6'
203
206
 
204
207
  around do |example|
205
208
  Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
@@ -316,7 +319,8 @@ describe Mongoid::Clients::Sessions do
316
319
  end
317
320
  end
318
321
 
319
- context 'when sessions are not supported', unless: sessions_supported? do
322
+ context 'when sessions are not supported' do
323
+ max_server_version '3.4'
320
324
 
321
325
  let!(:error) do
322
326
  e = nil
@@ -55,7 +55,8 @@ describe Mongoid::Clients::Sessions do
55
55
 
56
56
  context 'when a transaction is used on a model class' do
57
57
 
58
- context 'when transactions are supported', if: testing_transactions? do
58
+ context 'when transactions are supported' do
59
+ require_transaction_support
59
60
 
60
61
  around do |example|
61
62
  Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
@@ -191,7 +192,10 @@ describe Mongoid::Clients::Sessions do
191
192
  end
192
193
  end
193
194
 
194
- context 'when sessions are supported but transactions are not', if: sessions_supported? && !testing_transactions? do
195
+ context 'when sessions are supported but transactions are not' do
196
+ min_server_version '3.6'
197
+ # Could also test 4.0 in sharded cluster
198
+ max_server_version '3.6'
195
199
 
196
200
  let!(:error) do
197
201
  e = nil
@@ -222,7 +226,8 @@ describe Mongoid::Clients::Sessions do
222
226
  end
223
227
  end
224
228
 
225
- context 'when transactions are supported', if: testing_transactions? do
229
+ context 'when transactions are supported' do
230
+ require_transaction_support
226
231
 
227
232
  around do |example|
228
233
  Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
@@ -345,16 +350,23 @@ describe Mongoid::Clients::Sessions do
345
350
  end
346
351
  end
347
352
 
348
- context 'when sessions are supported but transactions are not', if: sessions_supported? && !testing_transactions? do
353
+ context 'when sessions are supported but transactions are not' do
354
+ min_server_version '3.6'
355
+ # Could also test 4.0 in sharded cluster
356
+ max_server_version '3.6'
349
357
 
350
358
  around do |example|
351
359
  Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
352
360
  Mongoid::Clients.with_name(:other).command(create: :people)
353
- subscriber.clear_events!
354
- person.with(client: :other) do
355
- example.run
361
+
362
+ begin
363
+ subscriber.clear_events!
364
+ person.with(client: :other) do
365
+ example.run
366
+ end
367
+ ensure
368
+ Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
356
369
  end
357
- Mongoid::Clients.with_name(:other).database.collections.each(&:drop)
358
370
  end
359
371
 
360
372
  let!(:error) do