mongoid 7.1.10 → 7.1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/config/locales/en.yml +13 -0
- 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/tasks/database.rb +1 -1
- data/lib/mongoid/version.rb +1 -1
- data/spec/app/models/mop.rb +26 -0
- data/spec/integration/contextual/empty_spec.rb +142 -0
- data/spec/mongoid/clients/factory_spec.rb +11 -0
- data/spec/mongoid/clients/options_spec.rb +11 -5
- data/spec/mongoid/config/environment_spec.rb +86 -8
- 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/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 +542 -532
- metadata.gz.sig +0 -0
@@ -83,9 +83,11 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
83
83
|
|
84
84
|
let!(:connections_and_cluster_during) do
|
85
85
|
connections = nil
|
86
|
-
cluster =
|
86
|
+
cluster = nil
|
87
|
+
Minim.with(options) do |klass|
|
87
88
|
klass.where(name: 'emily').to_a
|
88
89
|
connections = Minim.mongo_client.database.command(serverStatus: 1).first['connections']['current']
|
90
|
+
cluster = Minim.collection.cluster
|
89
91
|
end
|
90
92
|
[ connections, cluster ]
|
91
93
|
end
|
@@ -124,7 +126,10 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
124
126
|
end
|
125
127
|
|
126
128
|
it 'disconnects the new cluster when the block exits' do
|
127
|
-
expect(
|
129
|
+
expect(cluster_after).not_to be(cluster_during)
|
130
|
+
|
131
|
+
cluster_during.connected?.should be false
|
132
|
+
cluster_before.connected?.should be true
|
128
133
|
end
|
129
134
|
end
|
130
135
|
|
@@ -138,13 +143,14 @@ describe Mongoid::Clients::Options, retry: 3 do
|
|
138
143
|
|
139
144
|
it 'does not create a new cluster' do
|
140
145
|
expect(connections_during).to eq(connections_before)
|
146
|
+
|
147
|
+
cluster_during.should be cluster_before
|
141
148
|
end
|
142
149
|
|
143
150
|
it 'does not disconnect the original cluster' do
|
144
|
-
skip 'https://jira.mongodb.org/browse/MONGOID-5130'
|
145
|
-
|
146
|
-
expect(connections_after).to eq(connections_before)
|
147
151
|
expect(cluster_before).to be(cluster_after)
|
152
|
+
|
153
|
+
cluster_before.connected?.should be true
|
148
154
|
end
|
149
155
|
end
|
150
156
|
|
@@ -5,9 +5,19 @@ require "spec_helper"
|
|
5
5
|
|
6
6
|
describe Mongoid::Config::Environment do
|
7
7
|
|
8
|
-
|
9
|
-
Rails
|
10
|
-
|
8
|
+
around do |example|
|
9
|
+
if defined?(Rails)
|
10
|
+
SavedRails = Rails
|
11
|
+
example.run
|
12
|
+
Object.send(:remove_const, :Rails) if defined?(Rails)
|
13
|
+
Rails = SavedRails
|
14
|
+
Object.send(:remove_const, :SavedRails)
|
15
|
+
else
|
16
|
+
example.run
|
17
|
+
if defined?(Rails)
|
18
|
+
Object.send(:remove_const, :Rails)
|
19
|
+
end
|
20
|
+
end
|
11
21
|
end
|
12
22
|
|
13
23
|
describe "#env_name" do
|
@@ -24,11 +34,6 @@ describe Mongoid::Config::Environment do
|
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
27
|
-
after do
|
28
|
-
RailsTemp = Rails
|
29
|
-
Object.send(:remove_const, :Rails)
|
30
|
-
end
|
31
|
-
|
32
37
|
it "returns the rails environment" do
|
33
38
|
expect(described_class.env_name).to eq("production")
|
34
39
|
end
|
@@ -86,4 +91,77 @@ describe Mongoid::Config::Environment do
|
|
86
91
|
end
|
87
92
|
end
|
88
93
|
end
|
94
|
+
|
95
|
+
describe "#load_yaml" do
|
96
|
+
let(:path) { 'mongoid.yml' }
|
97
|
+
let(:environment) {}
|
98
|
+
before { allow(Rails).to receive('env').and_return('test') }
|
99
|
+
|
100
|
+
subject { described_class.load_yaml(path, environment) }
|
101
|
+
|
102
|
+
context 'when file not found' do
|
103
|
+
let(:path) { 'not/a/valid/path'}
|
104
|
+
|
105
|
+
it { expect { subject }.to raise_error(Errno::ENOENT) }
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when file found' do
|
109
|
+
before do
|
110
|
+
allow(File).to receive(:new).with('mongoid.yml').and_return(StringIO.new(file_contents))
|
111
|
+
end
|
112
|
+
|
113
|
+
let(:file_contents) do
|
114
|
+
<<~FILE
|
115
|
+
test:
|
116
|
+
clients: ['test']
|
117
|
+
development:
|
118
|
+
clients: ['dev']
|
119
|
+
FILE
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'when file cannot be parsed as YAML' do
|
123
|
+
let(:file_contents) { "*\nbad:%123abc" }
|
124
|
+
|
125
|
+
it { expect { subject }.to raise_error(Psych::SyntaxError) }
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when file contains ERB errors' do
|
129
|
+
let(:file_contents) { '<%= foo %>' }
|
130
|
+
|
131
|
+
it { expect { subject }.to raise_error(NameError) }
|
132
|
+
end
|
133
|
+
|
134
|
+
context 'when file is empty' do
|
135
|
+
let(:file_contents) { '' }
|
136
|
+
|
137
|
+
it { expect { subject }.to raise_error(Mongoid::Errors::EmptyConfigFile) }
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'when file does not contain a YAML Hash object' do
|
141
|
+
let(:file_contents) { '["this", "is", "an", "array"]' }
|
142
|
+
|
143
|
+
it { expect { subject }.to raise_error(Mongoid::Errors::InvalidConfigFile) }
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'when environment not specified' do
|
147
|
+
it 'uses the rails environment' do
|
148
|
+
is_expected.to eq("clients"=>["test"])
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when environment is specified' do
|
153
|
+
let(:environment) { 'development' }
|
154
|
+
|
155
|
+
it 'uses the specified environment' do
|
156
|
+
is_expected.to eq("clients"=>["dev"])
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context 'when environment is missing' do
|
161
|
+
let(:environment) { 'staging' }
|
162
|
+
|
163
|
+
it { is_expected.to be_nil }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
89
167
|
end
|
@@ -801,27 +801,28 @@ describe Mongoid::Contextual::Atomic do
|
|
801
801
|
context.unset(:name)
|
802
802
|
end
|
803
803
|
|
804
|
-
it "unsets the
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
expect(new_order.
|
804
|
+
it "unsets the fields from all documents" do
|
805
|
+
depeche_mode.reload
|
806
|
+
new_order.reload
|
807
|
+
expect(depeche_mode.name).to be_nil
|
808
|
+
expect(depeche_mode.years).to_not be_nil
|
809
|
+
expect(new_order.name).to be_nil
|
810
|
+
expect(new_order.years).to_not be_nil
|
810
811
|
end
|
811
812
|
end
|
812
813
|
|
813
814
|
context "when the field is aliased" do
|
814
|
-
|
815
815
|
before do
|
816
816
|
context.unset(:years)
|
817
817
|
end
|
818
818
|
|
819
|
-
it "unsets the
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
expect(new_order.
|
819
|
+
it "unsets the fields from all documents" do
|
820
|
+
depeche_mode.reload
|
821
|
+
new_order.reload
|
822
|
+
expect(depeche_mode.name).to_not be_nil
|
823
|
+
expect(depeche_mode.years).to be_nil
|
824
|
+
expect(new_order.name).to_not be_nil
|
825
|
+
expect(new_order.years).to be_nil
|
825
826
|
end
|
826
827
|
end
|
827
828
|
end
|
@@ -829,7 +830,8 @@ describe Mongoid::Contextual::Atomic do
|
|
829
830
|
context "when unsetting multiple fields" do
|
830
831
|
|
831
832
|
let!(:new_order) do
|
832
|
-
Band.create(name: "New Order", genres: [
|
833
|
+
Band.create(name: "New Order", genres: %w[electro dub], years: 10,
|
834
|
+
likes: 200, rating: 4.3, origin: 'Space')
|
833
835
|
end
|
834
836
|
|
835
837
|
let(:criteria) do
|
@@ -846,12 +848,13 @@ describe Mongoid::Contextual::Atomic do
|
|
846
848
|
context.unset(:name, :genres)
|
847
849
|
end
|
848
850
|
|
849
|
-
it "unsets
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
expect(new_order.
|
851
|
+
it "unsets the specified fields" do
|
852
|
+
new_order.reload
|
853
|
+
expect(new_order.name).to be_nil
|
854
|
+
expect(new_order.genres).to be_nil
|
855
|
+
expect(new_order.years).to_not be_nil
|
856
|
+
expect(new_order.likes).to_not be_nil
|
857
|
+
expect(new_order.rating).to_not be_nil
|
855
858
|
end
|
856
859
|
end
|
857
860
|
|
@@ -861,12 +864,46 @@ describe Mongoid::Contextual::Atomic do
|
|
861
864
|
context.unset(:name, :years)
|
862
865
|
end
|
863
866
|
|
864
|
-
it "unsets the
|
865
|
-
|
867
|
+
it "unsets the specified fields" do
|
868
|
+
new_order.reload
|
869
|
+
expect(new_order.name).to be_nil
|
870
|
+
expect(new_order.genres).to_not be_nil
|
871
|
+
expect(new_order.years).to be_nil
|
872
|
+
expect(new_order.likes).to_not be_nil
|
873
|
+
expect(new_order.rating).to_not be_nil
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
context "when using Hash arguments" do
|
878
|
+
|
879
|
+
before do
|
880
|
+
context.unset({ years: true, likes: "" }, { rating: false, origin: nil })
|
881
|
+
end
|
882
|
+
|
883
|
+
it "unsets the specified fields" do
|
884
|
+
new_order.reload
|
885
|
+
expect(new_order.name).to_not be_nil
|
886
|
+
expect(new_order.genres).to_not be_nil
|
887
|
+
expect(new_order.years).to be_nil
|
888
|
+
expect(new_order.likes).to be_nil
|
889
|
+
expect(new_order.rating).to be_nil
|
890
|
+
expect(new_order.origin).to be_nil
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
context "when mixing argument types" do
|
895
|
+
|
896
|
+
before do
|
897
|
+
context.unset(:name, [:years], { likes: "" }, { rating: false })
|
866
898
|
end
|
867
899
|
|
868
|
-
it "unsets the
|
869
|
-
|
900
|
+
it "unsets the specified fields" do
|
901
|
+
new_order.reload
|
902
|
+
expect(new_order.name).to be_nil
|
903
|
+
expect(new_order.genres).to_not be_nil
|
904
|
+
expect(new_order.years).to be_nil
|
905
|
+
expect(new_order.likes).to be_nil
|
906
|
+
expect(new_order.rating).to be_nil
|
870
907
|
end
|
871
908
|
end
|
872
909
|
end
|
@@ -895,7 +932,9 @@ describe Mongoid::Contextual::Atomic do
|
|
895
932
|
end
|
896
933
|
|
897
934
|
it "unsets the unaliased field" do
|
898
|
-
|
935
|
+
depeche_mode.reload
|
936
|
+
expect(depeche_mode.name).to be_nil
|
937
|
+
expect(depeche_mode.years).to_not be_nil
|
899
938
|
end
|
900
939
|
end
|
901
940
|
end
|
@@ -458,7 +458,7 @@ describe Mongoid::Document do
|
|
458
458
|
end
|
459
459
|
end
|
460
460
|
|
461
|
-
context ':compact option' do
|
461
|
+
context 'deprecated :compact option' do
|
462
462
|
# Since rails 6 differs in how it treats id fields,
|
463
463
|
# run this test on one version of rails. Currently rails 6 is in beta,
|
464
464
|
# when it is released this version should be changed to 6.
|
@@ -470,6 +470,26 @@ describe Mongoid::Document do
|
|
470
470
|
expect(church.as_json.keys.sort).to eq(%w(_id location name))
|
471
471
|
end
|
472
472
|
|
473
|
+
context 'deprecation' do
|
474
|
+
let(:church) do
|
475
|
+
Church.create!(name: 'St. Basil')
|
476
|
+
end
|
477
|
+
|
478
|
+
let(:message) do
|
479
|
+
'#as_json :compact option is deprecated. Please call #compact on the returned Hash object instead.'
|
480
|
+
end
|
481
|
+
|
482
|
+
it 'logs a deprecation warning when :compact is given' do
|
483
|
+
expect_any_instance_of(Logger).to receive(:warn).with(message)
|
484
|
+
church.as_json(compact: true)
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'does not log a deprecation warning when :compact is not given' do
|
488
|
+
expect_any_instance_of(Logger).to_not receive(:warn).with(message)
|
489
|
+
church.as_json
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
473
493
|
context 'there is a nil valued attribute' do
|
474
494
|
let(:church) do
|
475
495
|
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
|
@@ -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
|