mongoid 9.0.2 → 9.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mongoid/attributes/readonly.rb +8 -3
  3. data/lib/mongoid/clients/options.rb +14 -1
  4. data/lib/mongoid/clients/sessions.rb +1 -0
  5. data/lib/mongoid/criteria/queryable/selectable.rb +1 -1
  6. data/lib/mongoid/equality.rb +1 -0
  7. data/lib/mongoid/loadable.rb +72 -8
  8. data/lib/mongoid/matcher.rb +15 -1
  9. data/lib/mongoid/persistence_context.rb +14 -9
  10. data/lib/mongoid/railties/controller_runtime.rb +2 -2
  11. data/lib/mongoid/serializable.rb +7 -7
  12. data/lib/mongoid/threaded.rb +96 -28
  13. data/lib/mongoid/timestamps/timeless.rb +4 -1
  14. data/lib/mongoid/touchable.rb +1 -1
  15. data/lib/mongoid/traversable.rb +25 -2
  16. data/lib/mongoid/validatable/associated.rb +5 -2
  17. data/lib/mongoid/version.rb +1 -1
  18. data/spec/integration/active_job_spec.rb +24 -20
  19. data/spec/integration/app_spec.rb +9 -1
  20. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +4 -0
  21. data/spec/mongoid/attributes/readonly_spec.rb +19 -0
  22. data/spec/mongoid/clients/options_spec.rb +127 -2
  23. data/spec/mongoid/criteria/queryable/selectable_spec.rb +29 -0
  24. data/spec/mongoid/equality_spec.rb +6 -0
  25. data/spec/mongoid/interceptable_spec.rb +12 -0
  26. data/spec/mongoid/interceptable_spec_models.rb +12 -0
  27. data/spec/mongoid/loadable_spec.rb +86 -0
  28. data/spec/mongoid/persistence_context_spec.rb +39 -0
  29. data/spec/mongoid/railties/bson_object_id_serializer_spec.rb +18 -12
  30. data/spec/mongoid/threaded_spec.rb +24 -5
  31. data/spec/mongoid/validatable/associated_spec.rb +14 -4
  32. data/spec/rails/controller_extension/controller_runtime_spec.rb +14 -14
  33. metadata +7 -8
@@ -70,13 +70,16 @@ module Mongoid
70
70
  # Now, treating the target as an array, look at each element
71
71
  # and see if it is valid, but only if it has already been
72
72
  # persisted, or changed, and hasn't been flagged for destroy.
73
- list.all? do |value|
73
+ #
74
+ # use map.all? instead of just all?, because all? will do short-circuit
75
+ # evaluation and terminate on the first failed validation.
76
+ list.map do |value|
74
77
  if value && !value.flagged_for_destroy? && (!value.persisted? || value.changed?)
75
78
  value.validated? ? true : value.valid?
76
79
  else
77
80
  true
78
81
  end
79
- end
82
+ end.all?
80
83
  end
81
84
 
82
85
  document.errors.add(attribute, :invalid) unless valid
@@ -2,5 +2,5 @@
2
2
  # rubocop:todo all
3
3
 
4
4
  module Mongoid
5
- VERSION = "9.0.2"
5
+ VERSION = "9.0.4"
6
6
  end
@@ -2,31 +2,35 @@
2
2
  # rubocop:todo all
3
3
 
4
4
  require 'spec_helper'
5
- require 'active_job'
6
- require 'mongoid/railties/bson_object_id_serializer'
5
+ begin
6
+ require 'active_job'
7
+ require 'mongoid/railties/bson_object_id_serializer'
7
8
 
8
- describe 'ActiveJob Serialization' do
9
- skip unless defined?(ActiveJob)
9
+ describe 'ActiveJob Serialization' do
10
+ skip unless defined?(ActiveJob)
10
11
 
11
- class TestBsonObjectIdSerializerJob < ActiveJob::Base
12
- def perform(*args)
13
- args
12
+ class TestBsonObjectIdSerializerJob < ActiveJob::Base
13
+ def perform(*args)
14
+ args
15
+ end
14
16
  end
15
- end
16
17
 
17
- let(:band) do
18
- Band.create!
19
- end
18
+ let(:band) do
19
+ Band.create!
20
+ end
20
21
 
21
- before do
22
- ActiveJob::Serializers.add_serializers(
23
- [::Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer]
24
- )
25
- end
22
+ before do
23
+ ActiveJob::Serializers.add_serializers(
24
+ [::Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer]
25
+ )
26
+ end
26
27
 
27
- it 'serializes and deserializes BSON::ObjectId' do
28
- expect do
29
- TestBsonObjectIdSerializerJob.perform_later(band.id)
30
- end.not_to raise_error
28
+ it 'serializes and deserializes BSON::ObjectId' do
29
+ expect do
30
+ TestBsonObjectIdSerializerJob.perform_later(band.id)
31
+ end.not_to raise_error
32
+ end
31
33
  end
34
+ rescue LoadError
35
+ RSpec.context.skip 'This test requires active_job'
32
36
  end
@@ -36,6 +36,8 @@ describe 'Mongoid application tests' do
36
36
  context 'demo application' do
37
37
  context 'sinatra' do
38
38
  it 'runs' do
39
+ skip 'https://jira.mongodb.org/browse/MONGOID-5826'
40
+
39
41
  clone_application(
40
42
  'https://github.com/mongoid/mongoid-demo',
41
43
  subdir: 'sinatra-minimal',
@@ -55,6 +57,8 @@ describe 'Mongoid application tests' do
55
57
 
56
58
  context 'rails-api' do
57
59
  it 'runs' do
60
+ skip 'https://jira.mongodb.org/browse/MONGOID-5826'
61
+
58
62
  clone_application(
59
63
  'https://github.com/mongoid/mongoid-demo',
60
64
  subdir: 'rails-api',
@@ -172,7 +176,7 @@ describe 'Mongoid application tests' do
172
176
  if (rails_version = SpecConfig.instance.rails_version) == 'master'
173
177
  else
174
178
  check_call(%w(gem list))
175
- check_call(%w(gem install rails --no-document -v) + ["~> #{rails_version}.0"])
179
+ check_call(%w(gem install rails --no-document --force -v) + ["~> #{rails_version}.0"])
176
180
  end
177
181
  end
178
182
 
@@ -319,6 +323,10 @@ describe 'Mongoid application tests' do
319
323
  end
320
324
 
321
325
  def adjust_rails_defaults(rails_version: SpecConfig.instance.rails_version)
326
+ if !rails_version.match?(/^\d+\.\d+$/)
327
+ # This must be pre-release version, we trim it
328
+ rails_version = rails_version.split('.')[0..1].join('.')
329
+ end
322
330
  if File.exist?('config/application.rb')
323
331
  lines = IO.readlines('config/application.rb')
324
332
  lines.each do |line|
@@ -751,6 +751,10 @@ describe Mongoid::Association::Referenced::BelongsTo::Proxy do
751
751
  person.save!
752
752
  end
753
753
 
754
+ # NOTE: there as a bad interdependency here, with the auto_save_spec.rb
755
+ # file. If auto_save_spec.rb runs before this, the following specs fail
756
+ # with "undefined method `nullify' for an instance of Person".
757
+
754
758
  context "when parent exists" do
755
759
 
756
760
  context "when child is destroyed" do
@@ -266,7 +266,26 @@ describe Mongoid::Attributes::Readonly do
266
266
  expect(child.mother).to be_nil
267
267
  end
268
268
  end
269
+ end
270
+
271
+ context "when a subclass inherits readonly fields" do
272
+ let(:attributes) do
273
+ [:title, :terms]
274
+ end
275
+
276
+ before do
277
+ class OldPerson < Person
278
+ attr_readonly :age
279
+ end
280
+ end
269
281
 
282
+ it "ensures subclass inherits the readonly attributes from parent" do
283
+ expect(OldPerson.readonly_attributes.to_a).to include("title","terms")
284
+ end
285
+
286
+ it "ensures subclass does not modify parent's readonly attributes" do
287
+ expect(Person.readonly_attributes.to_a).not_to include("age")
288
+ end
270
289
  end
271
290
  end
272
291
  end
@@ -27,7 +27,7 @@ describe Mongoid::Clients::Options, retry: 3 do
27
27
  let(:options) { { database: 'other' } }
28
28
 
29
29
  it 'sets the options on the client' do
30
- expect(persistence_context.client.options['database']).to eq(options[:database])
30
+ expect(persistence_context.client.options['database'].to_s).to eq(options[:database].to_s)
31
31
  end
32
32
 
33
33
  it 'does not set the options on class level' do
@@ -319,7 +319,7 @@ describe Mongoid::Clients::Options, retry: 3 do
319
319
  end
320
320
 
321
321
  it 'sets the options on the client' do
322
- expect(persistence_context.client.options['database']).to eq(options[:database])
322
+ expect(persistence_context.client.options['database'].to_s).to eq(options[:database].to_s)
323
323
  end
324
324
 
325
325
  it 'does not set the options on instance level' do
@@ -522,4 +522,129 @@ describe Mongoid::Clients::Options, retry: 3 do
522
522
  end
523
523
  end
524
524
  end
525
+
526
+ context 'with global overrides' do
527
+ let(:default_subscriber) do
528
+ Mrss::EventSubscriber.new
529
+ end
530
+
531
+ let(:override_subscriber) do
532
+ Mrss::EventSubscriber.new
533
+ end
534
+
535
+ context 'when global client is overridden' do
536
+ before do
537
+ Mongoid.clients['override_client'] = { hosts: SpecConfig.instance.addresses, database: 'default_override_database' }
538
+ Mongoid.override_client('override_client')
539
+ Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
540
+ Mongoid.client('override_client').subscribe(Mongo::Monitoring::COMMAND, override_subscriber)
541
+ end
542
+
543
+ after do
544
+ Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
545
+ Mongoid.client('override_client').unsubscribe(Mongo::Monitoring::COMMAND, override_subscriber)
546
+ Mongoid.override_client(nil)
547
+ Mongoid.clients['override_client'] = nil
548
+ end
549
+
550
+ it 'uses the overridden client for create' do
551
+ Minim.create!
552
+
553
+ expect(override_subscriber.single_command_started_event('insert').database_name).to eq('default_override_database')
554
+ expect(default_subscriber.command_started_events('insert')).to be_empty
555
+ end
556
+
557
+ it 'uses the overridden client for queries' do
558
+ Minim.where(name: 'Dmitry').to_a
559
+
560
+ expect(override_subscriber.single_command_started_event('find').database_name).to eq('default_override_database')
561
+ expect(default_subscriber.command_started_events('find')).to be_empty
562
+ end
563
+
564
+ context 'when the client is set on the model level' do
565
+ let(:model_level_subscriber) do
566
+ Mrss::EventSubscriber.new
567
+ end
568
+
569
+ around(:example) do |example|
570
+ opts = Minim.storage_options
571
+ Minim.storage_options = Minim.storage_options.merge( { client: 'model_level_client' } )
572
+ Mongoid.clients['model_level_client'] = { hosts: SpecConfig.instance.addresses, database: 'model_level_database' }
573
+ Mongoid.client('model_level_client').subscribe(Mongo::Monitoring::COMMAND, override_subscriber)
574
+ example.run
575
+ Mongoid.client('model_level_client').unsubscribe(Mongo::Monitoring::COMMAND, override_subscriber)
576
+ Mongoid.clients['model_level_client'] = nil
577
+ Minim.storage_options = opts
578
+ end
579
+
580
+ # This behaviour is consistent with 8.x
581
+ it 'uses the overridden client for create' do
582
+ Minim.create!
583
+
584
+ expect(override_subscriber.single_command_started_event('insert').database_name).to eq('default_override_database')
585
+ expect(default_subscriber.command_started_events('insert')).to be_empty
586
+ expect(model_level_subscriber.command_started_events('insert')).to be_empty
587
+ end
588
+
589
+ # This behaviour is consistent with 8.x
590
+ it 'uses the overridden client for queries' do
591
+ Minim.where(name: 'Dmitry').to_a
592
+
593
+ expect(override_subscriber.single_command_started_event('find').database_name).to eq('default_override_database')
594
+ expect(default_subscriber.command_started_events('find')).to be_empty
595
+ expect(model_level_subscriber.command_started_events('find')).to be_empty
596
+ end
597
+ end
598
+ end
599
+
600
+ context 'when global database is overridden' do
601
+ before do
602
+ Mongoid.override_database('override_database')
603
+ Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
604
+ end
605
+
606
+ after do
607
+ Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
608
+ Mongoid.override_database(nil)
609
+ end
610
+
611
+ it 'uses the overridden database for create' do
612
+ Minim.create!
613
+
614
+ expect(default_subscriber.single_command_started_event('insert').database_name).to eq('override_database')
615
+ end
616
+
617
+ it 'uses the overridden database for queries' do
618
+ Minim.where(name: 'Dmitry').to_a
619
+
620
+ expect(default_subscriber.single_command_started_event('find').database_name).to eq('override_database')
621
+ end
622
+
623
+ context 'when the database is set on the model level' do
624
+ around(:example) do |example|
625
+ opts = Minim.storage_options
626
+ Minim.storage_options = Minim.storage_options.merge( { database: 'model_level_database' } )
627
+ Mongoid.clients['model_level_client'] = { hosts: SpecConfig.instance.addresses, database: 'model_level_database' }
628
+ Mongoid.client(:default).subscribe(Mongo::Monitoring::COMMAND, default_subscriber)
629
+ example.run
630
+ Mongoid.client(:default).unsubscribe(Mongo::Monitoring::COMMAND, default_subscriber)
631
+ Mongoid.clients['model_level_client'] = nil
632
+ Minim.storage_options = opts
633
+ end
634
+
635
+ # This behaviour is consistent with 8.x
636
+ it 'uses the overridden database for create' do
637
+ Minim.create!
638
+
639
+ expect(default_subscriber.single_command_started_event('insert').database_name).to eq('override_database')
640
+ end
641
+
642
+ it 'uses the overridden database for queries' do
643
+ Minim.where(name: 'Dmitry').to_a
644
+
645
+ expect(default_subscriber.single_command_started_event('find').database_name).to eq('override_database')
646
+ end
647
+ end
648
+ end
649
+ end
525
650
  end
@@ -1939,6 +1939,35 @@ describe Mongoid::Criteria::Queryable::Selectable do
1939
1939
  end
1940
1940
  end
1941
1941
 
1942
+ describe "#not" do
1943
+ context "when negating a criterion" do
1944
+ let(:selection) do
1945
+ query.not(field: /value/)
1946
+ end
1947
+
1948
+ it "adds the $not selector" do
1949
+ expect(selection.selector).to eq({
1950
+ "field" => { "$not" => /value/ }
1951
+ })
1952
+ end
1953
+
1954
+ it "returns a cloned query" do
1955
+ expect(selection).to_not equal(query)
1956
+ end
1957
+
1958
+ context "when toggling negation state" do
1959
+ it "negates the negating value" do
1960
+ expect(query.negating).to be_nil
1961
+ negated_query = query.not
1962
+ expect(negated_query.negating).to be true
1963
+ double_negated_query = negated_query.not
1964
+ expect(double_negated_query.negating).to be false
1965
+ end
1966
+ end
1967
+ end
1968
+ end
1969
+
1970
+
1942
1971
  describe Symbol do
1943
1972
 
1944
1973
  describe "#all" do
@@ -189,6 +189,12 @@ describe Mongoid::Equality do
189
189
  it "compares based on the document id" do
190
190
  expect(first <=> second).to eq(-1)
191
191
  end
192
+
193
+ it "doesn't break if one isn't a document" do
194
+ expect do
195
+ first <=> "Foo"
196
+ end.to_not raise_error
197
+ end
192
198
  end
193
199
 
194
200
  describe "#eql?" do
@@ -1789,6 +1789,12 @@ describe Mongoid::Interceptable do
1789
1789
  context 'with around callbacks' do
1790
1790
  config_override :around_callbacks_for_embeds, true
1791
1791
 
1792
+ after do
1793
+ Mongoid::Threaded.stack('interceptable').clear
1794
+ end
1795
+
1796
+ let(:stack) { Mongoid::Threaded.stack('interceptable') }
1797
+
1792
1798
  let(:expected) do
1793
1799
  [
1794
1800
  [InterceptableSpec::CbCascadedChild, :before_validation],
@@ -1824,6 +1830,12 @@ describe Mongoid::Interceptable do
1824
1830
  parent.save!
1825
1831
  expect(registry.calls).to eq expected
1826
1832
  end
1833
+
1834
+ it 'shows that cascaded callbacks can access Mongoid state' do
1835
+ expect(stack).to be_empty
1836
+ parent.save!
1837
+ expect(stack).not_to be_empty
1838
+ end
1827
1839
  end
1828
1840
 
1829
1841
  context 'without around callbacks' do
@@ -224,7 +224,19 @@ module InterceptableSpec
224
224
 
225
225
  attr_accessor :callback_registry
226
226
 
227
+ before_save :test_mongoid_state
228
+
227
229
  include CallbackTracking
230
+
231
+ private
232
+
233
+ # Helps test that cascading child callbacks have access to the Mongoid
234
+ # state objects; if the implementation uses fiber-local (instead of truly
235
+ # thread-local) variables, the related tests will fail because the
236
+ # cascading child callbacks use fibers to linearize the recursion.
237
+ def test_mongoid_state
238
+ Mongoid::Threaded.stack('interceptable').push(self)
239
+ end
228
240
  end
229
241
  end
230
242
 
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Mongoid::Loadable do
6
+ let(:lib_dir) { Pathname.new('../../lib').realpath(__dir__) }
7
+
8
+ shared_context 'with ignore_patterns' do
9
+ around do |example|
10
+ saved = Mongoid.ignore_patterns
11
+ Mongoid.ignore_patterns = ignore_patterns
12
+ example.run
13
+ ensure
14
+ Mongoid.ignore_patterns = saved
15
+ end
16
+ end
17
+
18
+ describe '#ignore_patterns' do
19
+ context 'when not explicitly set' do
20
+ it 'equals the default list of ignore patterns' do
21
+ expect(Mongoid.ignore_patterns).to eq Mongoid::Loadable::DEFAULT_IGNORE_PATTERNS
22
+ end
23
+ end
24
+
25
+ context 'when explicitly set' do
26
+ include_context 'with ignore_patterns'
27
+
28
+ let(:ignore_patterns) { %w[ pattern1 pattern2 ] }
29
+
30
+ it 'equals the list of specified patterns' do
31
+ expect(Mongoid.ignore_patterns).to eq ignore_patterns
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#files_under_path' do
37
+ let(:results) { Mongoid.files_under_path(lib_dir) }
38
+
39
+ include_context 'with ignore_patterns'
40
+
41
+ context 'when ignore_patterns is empty' do
42
+ let(:ignore_patterns) { [] }
43
+
44
+ it 'returns all ruby files' do
45
+ expect(results.length).to be > 10 # should be a bunch of them
46
+ expect(results).to include('rails/mongoid')
47
+ end
48
+ end
49
+
50
+ context 'when ignore_patterns is not empty' do
51
+ let(:ignore_patterns) { %w[ */rails/* ] }
52
+
53
+ it 'omits the ignored paths' do
54
+ expect(results.length).to be > 10 # should be a bunch of them
55
+ expect(results).not_to include('rails/mongoid')
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#files_under_paths' do
61
+ let(:paths) { [ lib_dir.join('mongoid'), lib_dir.join('rails') ] }
62
+ let(:results) { Mongoid.files_under_paths(paths) }
63
+
64
+ include_context 'with ignore_patterns'
65
+
66
+ context 'when ignore_patterns is empty' do
67
+ let(:ignore_patterns) { [] }
68
+
69
+ it 'returns all ruby files' do
70
+ expect(results.length).to be > 10 # should be a bunch
71
+ expect(results).to include('generators/mongoid/model/model_generator')
72
+ expect(results).to include('fields/encrypted')
73
+ end
74
+ end
75
+
76
+ context 'when ignore_patterns is not empty' do
77
+ let(:ignore_patterns) { %w[ */model/* */fields/* ] }
78
+
79
+ it 'returns all ruby files' do
80
+ expect(results.length).to be > 10 # should be a bunch
81
+ expect(results).not_to include('generators/mongoid/model/model_generator')
82
+ expect(results).not_to include('fields/encrypted')
83
+ end
84
+ end
85
+ end
86
+ end
@@ -536,6 +536,20 @@ describe Mongoid::PersistenceContext do
536
536
  end
537
537
  end
538
538
  end
539
+
540
+ context 'when the database is specified as a proc' do
541
+ let(:options) { { database: ->{ 'other' } } }
542
+
543
+ after { persistence_context.client.close }
544
+
545
+ it 'evaluates the proc' do
546
+ expect(persistence_context.database_name).to eq(:other)
547
+ end
548
+
549
+ it 'does not pass the proc to the client' do
550
+ expect(persistence_context.client.database.name).to eq('other')
551
+ end
552
+ end
539
553
  end
540
554
 
541
555
  describe '#client' do
@@ -570,6 +584,14 @@ describe Mongoid::PersistenceContext do
570
584
  expect(persistence_context.client).to eq(Mongoid::Clients.with_name(:alternative))
571
585
  end
572
586
 
587
+ context 'when the client option is a proc' do
588
+ let(:options) { { client: -> { :alternative } } }
589
+
590
+ it 'evaluates the proc' do
591
+ expect(persistence_context.client).to eq(Mongoid::Clients.with_name(:alternative))
592
+ end
593
+ end
594
+
573
595
  context 'when there is a client override' do
574
596
  persistence_context_override :client, :other
575
597
 
@@ -608,6 +630,23 @@ describe Mongoid::PersistenceContext do
608
630
  end
609
631
  end
610
632
 
633
+ context 'when the client is set as a proc in the storage options' do
634
+ let(:options) { {} }
635
+
636
+ before do
637
+ Band.store_in client: ->{ :alternative }
638
+ end
639
+
640
+ after do
641
+ persistence_context.client.close
642
+ Band.store_in client: nil
643
+ end
644
+
645
+ it 'uses the client option' do
646
+ expect(persistence_context.client).to eq(Mongoid::Clients.with_name(:alternative))
647
+ end
648
+ end
649
+
611
650
  context 'when there is no client option set' do
612
651
 
613
652
  let(:options) do
@@ -2,23 +2,29 @@
2
2
  # rubocop:todo all
3
3
 
4
4
  require 'spec_helper'
5
- require 'active_job'
6
- require 'mongoid/railties/bson_object_id_serializer'
7
5
 
8
- describe 'Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer' do
6
+ begin
7
+ require 'active_job'
8
+ require 'mongoid/railties/bson_object_id_serializer'
9
9
 
10
- let(:serializer) { Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer.instance }
11
- let(:object_id) { BSON::ObjectId.new }
12
10
 
13
- describe '#serialize' do
14
- it 'serializes BSON::ObjectId' do
15
- expect(serializer.serialize(object_id)).to be_a(String)
11
+ describe 'Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer' do
12
+
13
+ let(:serializer) { Mongoid::Railties::ActiveJobSerializers::BsonObjectIdSerializer.instance }
14
+ let(:object_id) { BSON::ObjectId.new }
15
+
16
+ describe '#serialize' do
17
+ it 'serializes BSON::ObjectId' do
18
+ expect(serializer.serialize(object_id)).to be_a(String)
19
+ end
16
20
  end
17
- end
18
21
 
19
- describe '#deserialize' do
20
- it 'deserializes BSON::ObjectId' do
21
- expect(serializer.deserialize(serializer.serialize(object_id))).to eq(object_id)
22
+ describe '#deserialize' do
23
+ it 'deserializes BSON::ObjectId' do
24
+ expect(serializer.deserialize(serializer.serialize(object_id))).to eq(object_id)
25
+ end
22
26
  end
23
27
  end
28
+ rescue LoadError
29
+ RSpec.context.skip 'This test requires active_job'
24
30
  end
@@ -36,11 +36,11 @@ describe Mongoid::Threaded do
36
36
  context "when the stack has elements" do
37
37
 
38
38
  before do
39
- Thread.current["[mongoid]:load-stack"] = [ true ]
39
+ described_class.stack('load').push(true)
40
40
  end
41
41
 
42
42
  after do
43
- Thread.current["[mongoid]:load-stack"] = []
43
+ described_class.stack('load').clear
44
44
  end
45
45
 
46
46
  it "returns true" do
@@ -51,7 +51,7 @@ describe Mongoid::Threaded do
51
51
  context "when the stack has no elements" do
52
52
 
53
53
  before do
54
- Thread.current["[mongoid]:load-stack"] = []
54
+ described_class.stack('load').clear
55
55
  end
56
56
 
57
57
  it "returns false" do
@@ -76,7 +76,7 @@ describe Mongoid::Threaded do
76
76
  context "when a stack has been initialized" do
77
77
 
78
78
  before do
79
- Thread.current["[mongoid]:load-stack"] = [ true ]
79
+ described_class.stack('load').push(true)
80
80
  end
81
81
 
82
82
  let(:loading) do
@@ -84,7 +84,7 @@ describe Mongoid::Threaded do
84
84
  end
85
85
 
86
86
  after do
87
- Thread.current["[mongoid]:load-stack"] = []
87
+ described_class.stack('load').clear
88
88
  end
89
89
 
90
90
  it "returns the stack" do
@@ -341,4 +341,23 @@ describe Mongoid::Threaded do
341
341
  end
342
342
  end
343
343
  end
344
+
345
+ describe '#clear_modified_documents' do
346
+ let(:session) do
347
+ double(Mongo::Session).tap do |session|
348
+ allow(session).to receive(:in_transaction?).and_return(true)
349
+ end
350
+ end
351
+
352
+ context 'when there are modified documents' do
353
+ before do
354
+ described_class.add_modified_document(session, Minim.new)
355
+ described_class.clear_modified_documents(session)
356
+ end
357
+
358
+ it 'removes the documents and keys' do
359
+ expect(described_class.modified_documents).to be_empty
360
+ end
361
+ end
362
+ end
344
363
  end