mongoid 7.3.2 → 7.3.3
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/config/locales/en.yml +13 -0
- data/lib/mongoid/association/referenced/has_many/enumerable.rb +3 -7
- data/lib/mongoid/association/relatable.rb +2 -0
- data/lib/mongoid/atomic.rb +26 -2
- data/lib/mongoid/config/environment.rb +9 -1
- data/lib/mongoid/contextual/atomic.rb +7 -2
- data/lib/mongoid/contextual/none.rb +3 -0
- data/lib/mongoid/criteria/queryable/selectable.rb +2 -2
- data/lib/mongoid/criteria/queryable/storable.rb +4 -4
- data/lib/mongoid/document.rb +3 -2
- data/lib/mongoid/errors/empty_config_file.rb +26 -0
- data/lib/mongoid/errors/invalid_config_file.rb +26 -0
- data/lib/mongoid/errors.rb +2 -0
- data/lib/mongoid/persistence_context.rb +3 -1
- data/lib/mongoid/query_cache.rb +11 -1
- data/lib/mongoid/tasks/database.rb +1 -1
- data/lib/mongoid/touchable.rb +10 -0
- data/lib/mongoid/version.rb +1 -1
- data/spec/integration/contextual/empty_spec.rb +142 -0
- data/spec/integration/stringified_symbol_field_spec.rb +2 -2
- data/spec/mongoid/association/referenced/belongs_to_query_spec.rb +20 -0
- data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +244 -92
- data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +6 -6
- data/spec/mongoid/association/referenced/has_many_models.rb +17 -0
- data/spec/mongoid/clients/factory_spec.rb +9 -3
- data/spec/mongoid/clients/options_spec.rb +11 -5
- data/spec/mongoid/config/environment_spec.rb +86 -8
- data/spec/mongoid/config_spec.rb +89 -16
- data/spec/mongoid/contextual/atomic_spec.rb +64 -25
- data/spec/mongoid/contextual/geo_near_spec.rb +1 -1
- data/spec/mongoid/document_spec.rb +21 -1
- data/spec/mongoid/errors/invalid_config_file_spec.rb +32 -0
- data/spec/mongoid/persistable/updatable_spec.rb +2 -0
- data/spec/mongoid/query_cache_spec.rb +24 -0
- data/spec/mongoid/touchable_spec.rb +18 -0
- data/spec/mongoid/touchable_spec_models.rb +2 -0
- data/spec/shared/lib/mrss/constraints.rb +21 -4
- data/spec/shared/lib/mrss/event_subscriber.rb +200 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +17 -12
- data/spec/shared/share/Dockerfile.erb +5 -4
- data/spec/shared/shlib/server.sh +71 -21
- data.tar.gz.sig +0 -0
- metadata +581 -573
- metadata.gz.sig +0 -0
@@ -501,7 +501,7 @@ describe Mongoid::Document do
|
|
501
501
|
end
|
502
502
|
end
|
503
503
|
|
504
|
-
context ':compact option' do
|
504
|
+
context 'deprecated :compact option' do
|
505
505
|
# Since rails 6 differs in how it treats id fields,
|
506
506
|
# run this test on one version of rails. Currently rails 6 is in beta,
|
507
507
|
# when it is released this version should be changed to 6.
|
@@ -513,6 +513,26 @@ describe Mongoid::Document do
|
|
513
513
|
expect(church.as_json.keys.sort).to eq(%w(_id location name))
|
514
514
|
end
|
515
515
|
|
516
|
+
context 'deprecation' do
|
517
|
+
let(:church) do
|
518
|
+
Church.create!(name: 'St. Basil')
|
519
|
+
end
|
520
|
+
|
521
|
+
let(:message) do
|
522
|
+
'#as_json :compact option is deprecated. Please call #compact on the returned Hash object instead.'
|
523
|
+
end
|
524
|
+
|
525
|
+
it 'logs a deprecation warning when :compact is given' do
|
526
|
+
expect_any_instance_of(Logger).to receive(:warn).with(message)
|
527
|
+
church.as_json(compact: true)
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'does not log a deprecation warning when :compact is not given' do
|
531
|
+
expect_any_instance_of(Logger).to_not receive(:warn).with(message)
|
532
|
+
church.as_json
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
516
536
|
context 'there is a nil valued attribute' do
|
517
537
|
let(:church) do
|
518
538
|
Church.create!(name: 'St. Basil')
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require "spec_helper"
|
5
|
+
|
6
|
+
describe Mongoid::Errors::InvalidConfigFile do
|
7
|
+
|
8
|
+
describe "#message" do
|
9
|
+
|
10
|
+
let(:error) do
|
11
|
+
described_class.new('/my/path')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "contains the problem in the message" do
|
15
|
+
expect(error.message).to include(
|
16
|
+
"Invalid configuration file: /my/path."
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "contains the summary in the message" do
|
21
|
+
expect(error.message).to include(
|
22
|
+
"Your mongoid.yml configuration file does not contain the"
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "contains the resolution in the message" do
|
27
|
+
expect(error.message).to include(
|
28
|
+
"Ensure your configuration file contains the correct contents."
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -458,6 +458,7 @@ describe Mongoid::Persistable::Updatable do
|
|
458
458
|
describe "##{method}" do
|
459
459
|
|
460
460
|
context "when saving with a hash field with invalid keys" do
|
461
|
+
max_server_version '4.9'
|
461
462
|
|
462
463
|
let(:person) do
|
463
464
|
Person.create
|
@@ -494,6 +495,7 @@ describe Mongoid::Persistable::Updatable do
|
|
494
495
|
end
|
495
496
|
|
496
497
|
context "when the document has been destroyed" do
|
498
|
+
max_server_version '4.9'
|
497
499
|
|
498
500
|
let(:person) do
|
499
501
|
Person.create
|
@@ -24,10 +24,27 @@ describe Mongoid::QueryCache do
|
|
24
24
|
SessionRegistry.instance.verify_sessions_ended!
|
25
25
|
end
|
26
26
|
|
27
|
+
let(:reset_legacy_qc_warning) do
|
28
|
+
begin
|
29
|
+
Mongoid::QueryCache.remove_instance_variable('@legacy_query_cache_warned')
|
30
|
+
rescue NameError
|
31
|
+
# raised if the instance variable wasn't set
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
27
35
|
describe '#cache' do
|
28
36
|
context 'with driver query cache' do
|
29
37
|
min_driver_version '2.14'
|
30
38
|
|
39
|
+
it 'does not log a deprecation warning' do
|
40
|
+
reset_legacy_qc_warning
|
41
|
+
|
42
|
+
expect_any_instance_of(Logger).to_not receive(:warn).with(
|
43
|
+
described_class::LEGACY_WARNING
|
44
|
+
)
|
45
|
+
described_class.cache { }
|
46
|
+
end
|
47
|
+
|
31
48
|
context 'when query cache is not enabled' do
|
32
49
|
before do
|
33
50
|
Mongoid::QueryCache.enabled = false
|
@@ -180,6 +197,13 @@ describe Mongoid::QueryCache do
|
|
180
197
|
context 'with mongoid query cache' do
|
181
198
|
max_driver_version '2.13'
|
182
199
|
|
200
|
+
it 'logs a deprecation warning' do
|
201
|
+
reset_legacy_qc_warning
|
202
|
+
|
203
|
+
expect_any_instance_of(Logger).to receive(:warn).with(described_class::LEGACY_WARNING)
|
204
|
+
described_class.cache { }
|
205
|
+
end
|
206
|
+
|
183
207
|
context 'when query cache is not enabled' do
|
184
208
|
before do
|
185
209
|
Mongoid::QueryCache.enabled = false
|
@@ -132,6 +132,24 @@ describe Mongoid::Touchable do
|
|
132
132
|
include_examples 'updates the child'
|
133
133
|
include_examples 'updates the parent when :touch is true'
|
134
134
|
include_examples 'updates the parent when :touch is not set'
|
135
|
+
|
136
|
+
context 'when also updating an additional field' do
|
137
|
+
it 'persists the update to the additional field' do
|
138
|
+
entrance
|
139
|
+
update_time
|
140
|
+
entrance.touch(:last_used_at)
|
141
|
+
|
142
|
+
entrance.reload
|
143
|
+
building.reload
|
144
|
+
|
145
|
+
# This is the assertion we want.
|
146
|
+
entrance.last_used_at.should == update_time
|
147
|
+
|
148
|
+
# Check other timestamps for good measure.
|
149
|
+
entrance.updated_at.should == update_time
|
150
|
+
building.updated_at.should == update_time
|
151
|
+
end
|
152
|
+
end
|
135
153
|
end
|
136
154
|
|
137
155
|
context "when the document is referenced" do
|
@@ -257,22 +257,39 @@ module Mrss
|
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
260
|
-
def
|
260
|
+
def require_multi_mongos
|
261
261
|
before(:all) do
|
262
262
|
if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length == 1
|
263
|
-
skip 'Test requires a minimum of two
|
263
|
+
skip 'Test requires a minimum of two mongoses if run in sharded topology'
|
264
|
+
end
|
265
|
+
|
266
|
+
if ClusterConfig.instance.topology == :load_balanced && SpecConfig.instance.single_mongos?
|
267
|
+
skip 'Test requires a minimum of two mongoses if run in load-balanced topology'
|
264
268
|
end
|
265
269
|
end
|
266
270
|
end
|
267
271
|
|
268
|
-
|
272
|
+
# In sharded topology operations are distributed to the mongoses.
|
273
|
+
# When we set fail points, the fail point may be set on one mongos and
|
274
|
+
# operation may be executed on another mongos, causing failures.
|
275
|
+
# Tests that are not setting targeted fail points should utilize this
|
276
|
+
# method to restrict themselves to single mongos.
|
277
|
+
#
|
278
|
+
# In load-balanced topology, the same problem can happen when there is
|
279
|
+
# more than one mongos behind the load balancer.
|
280
|
+
def require_no_multi_mongos
|
269
281
|
before(:all) do
|
270
282
|
if ClusterConfig.instance.topology == :sharded && SpecConfig.instance.addresses.length > 1
|
271
|
-
skip 'Test requires a single
|
283
|
+
skip 'Test requires a single mongos if run in sharded topology'
|
284
|
+
end
|
285
|
+
if ClusterConfig.instance.topology == :load_balanced && !SpecConfig.instance.single_mongos?
|
286
|
+
skip 'Test requires a single mongos, as indicated by SINGLE_MONGOS=1 environment variable, if run in load-balanced topology'
|
272
287
|
end
|
273
288
|
end
|
274
289
|
end
|
275
290
|
|
291
|
+
alias :require_no_multi_shard :require_no_multi_mongos
|
292
|
+
|
276
293
|
def require_wired_tiger
|
277
294
|
before(:all) do
|
278
295
|
# Storage detection fails for serverless instances. However, it is safe to
|
@@ -0,0 +1,200 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mrss
|
4
|
+
# Test event subscriber.
|
5
|
+
class EventSubscriber
|
6
|
+
|
7
|
+
# The mappings of event names to types.
|
8
|
+
MAPPINGS = {
|
9
|
+
'topology_opening_event' => Mongo::Monitoring::Event::TopologyOpening,
|
10
|
+
'topology_description_changed_event' => Mongo::Monitoring::Event::TopologyChanged,
|
11
|
+
'topology_closed_event' => Mongo::Monitoring::Event::TopologyClosed,
|
12
|
+
'server_opening_event' => Mongo::Monitoring::Event::ServerOpening,
|
13
|
+
'server_description_changed_event' => Mongo::Monitoring::Event::ServerDescriptionChanged,
|
14
|
+
'server_closed_event' => Mongo::Monitoring::Event::ServerClosed
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
attr_reader :all_events
|
18
|
+
|
19
|
+
attr_reader :started_events
|
20
|
+
|
21
|
+
attr_reader :succeeded_events
|
22
|
+
|
23
|
+
attr_reader :failed_events
|
24
|
+
|
25
|
+
attr_reader :published_events
|
26
|
+
|
27
|
+
# @param [ String ] name Optional name for the event subscriber.
|
28
|
+
def initialize(name: nil)
|
29
|
+
@mutex = Mutex.new
|
30
|
+
clear_events!
|
31
|
+
@name = name
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
%Q`#<EventSubscriber:#{@name ? "\"#{@name}\"" : '%x' % object_id} \
|
36
|
+
started=#{started_events.length} \
|
37
|
+
succeeded=#{succeeded_events.length} \
|
38
|
+
failed=#{failed_events.length} \
|
39
|
+
published=#{published_events.length}>`
|
40
|
+
end
|
41
|
+
|
42
|
+
alias :inspect :to_s
|
43
|
+
|
44
|
+
# Event retrieval
|
45
|
+
|
46
|
+
def select_started_events(cls)
|
47
|
+
started_events.select do |event|
|
48
|
+
event.is_a?(cls)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def select_succeeded_events(cls)
|
53
|
+
succeeded_events.select do |event|
|
54
|
+
event.is_a?(cls)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def select_completed_events(*classes)
|
59
|
+
(succeeded_events + failed_events).select do |event|
|
60
|
+
classes.any? { |c| c === event }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def select_published_events(cls)
|
65
|
+
published_events.select do |event|
|
66
|
+
event.is_a?(cls)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Filters command started events for the specified command name.
|
71
|
+
def command_started_events(command_name)
|
72
|
+
started_events.select do |event|
|
73
|
+
event.command[command_name]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def non_auth_command_started_events
|
78
|
+
started_events.reject do |event|
|
79
|
+
%w(authenticate getnonce saslSstart saslContinue).any? do |cmd|
|
80
|
+
event.command[cmd]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Locates command stated events for the specified command name,
|
86
|
+
# asserts that there is exactly one such event, and returns it.
|
87
|
+
def single_command_started_event(command_name, include_auth: false)
|
88
|
+
events = if include_auth
|
89
|
+
started_events
|
90
|
+
else
|
91
|
+
non_auth_command_started_events
|
92
|
+
end
|
93
|
+
events.select! do |event|
|
94
|
+
event.command[command_name]
|
95
|
+
end
|
96
|
+
if events.length != 1
|
97
|
+
raise "Expected a single #{command_name} event but we have #{events.length}"
|
98
|
+
end
|
99
|
+
events.first
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Get the first succeeded event published for the name, and then delete it.
|
104
|
+
#
|
105
|
+
# @param [ String ] name The event name.
|
106
|
+
#
|
107
|
+
# @return [ Event ] The matching event.
|
108
|
+
def first_event(name)
|
109
|
+
cls = MAPPINGS[name]
|
110
|
+
if cls.nil?
|
111
|
+
raise ArgumentError, "Bogus event name #{name}"
|
112
|
+
end
|
113
|
+
matching = succeeded_events.find do |event|
|
114
|
+
cls === event
|
115
|
+
end
|
116
|
+
succeeded_events.delete(matching)
|
117
|
+
matching
|
118
|
+
end
|
119
|
+
|
120
|
+
# Event recording
|
121
|
+
|
122
|
+
# Cache the started event.
|
123
|
+
#
|
124
|
+
# @param [ Event ] event The event.
|
125
|
+
def started(event)
|
126
|
+
@mutex.synchronize do
|
127
|
+
started_events << event
|
128
|
+
all_events << event
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Cache the succeeded event.
|
133
|
+
#
|
134
|
+
# @param [ Event ] event The event.
|
135
|
+
def succeeded(event)
|
136
|
+
@mutex.synchronize do
|
137
|
+
succeeded_events << event
|
138
|
+
all_events << event
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Cache the failed event.
|
143
|
+
#
|
144
|
+
# @param [ Event ] event The event.
|
145
|
+
def failed(event)
|
146
|
+
@mutex.synchronize do
|
147
|
+
failed_events << event
|
148
|
+
all_events << event
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def published(event)
|
153
|
+
@mutex.synchronize do
|
154
|
+
published_events << event
|
155
|
+
all_events << event
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Clear all cached events.
|
160
|
+
def clear_events!
|
161
|
+
@all_events = []
|
162
|
+
@started_events = []
|
163
|
+
@succeeded_events = []
|
164
|
+
@failed_events = []
|
165
|
+
@published_events = []
|
166
|
+
self
|
167
|
+
end
|
168
|
+
end
|
169
|
+
# Only handles succeeded events correctly.
|
170
|
+
class PhasedEventSubscriber < EventSubscriber
|
171
|
+
def initialize
|
172
|
+
super
|
173
|
+
@phase_events = {}
|
174
|
+
end
|
175
|
+
|
176
|
+
def phase_finished(phase_index)
|
177
|
+
@phase_events[phase_index] = succeeded_events
|
178
|
+
@succeeded_events = []
|
179
|
+
end
|
180
|
+
|
181
|
+
def phase_events(phase_index)
|
182
|
+
@phase_events[phase_index]
|
183
|
+
end
|
184
|
+
|
185
|
+
def event_count
|
186
|
+
@phase_events.inject(0) do |sum, event|
|
187
|
+
sum + event.length
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
class VerboseEventSubscriber < EventSubscriber
|
193
|
+
%w(started succeeded failed published).each do |meth|
|
194
|
+
define_method(meth) do |event|
|
195
|
+
puts event.summary
|
196
|
+
super(event)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
@@ -48,19 +48,24 @@ module Mrss
|
|
48
48
|
url = dl['archive']['url']
|
49
49
|
end
|
50
50
|
rescue MissingDownloadUrl
|
51
|
-
if %w(
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
ensure
|
61
|
-
io.close
|
62
|
-
end
|
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'
|
63
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')
|
64
69
|
else
|
65
70
|
raise
|
66
71
|
end
|