tantot 0.1.5 → 0.1.6
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
- data/lib/tantot.rb +7 -23
- data/lib/tantot/agent.rb +19 -0
- data/lib/tantot/agent/base.rb +71 -0
- data/lib/tantot/agent/block.rb +32 -0
- data/lib/tantot/agent/registry.rb +34 -0
- data/lib/tantot/agent/watcher.rb +46 -0
- data/lib/tantot/changes.rb +2 -3
- data/lib/tantot/config.rb +2 -2
- data/lib/tantot/errors.rb +6 -0
- data/lib/tantot/extensions/chewy.rb +66 -18
- data/lib/tantot/extensions/grape/middleware.rb +1 -1
- data/lib/tantot/manager.rb +31 -0
- data/lib/tantot/observe.rb +36 -31
- data/lib/tantot/railtie.rb +5 -0
- data/lib/tantot/strategy.rb +24 -0
- data/lib/tantot/{performer → strategy}/bypass.rb +2 -2
- data/lib/tantot/strategy/chewy.rb +33 -0
- data/lib/tantot/strategy/inline.rb +9 -0
- data/lib/tantot/strategy/sidekiq.rb +36 -0
- data/lib/tantot/version.rb +1 -1
- data/performance/profile.rb +12 -8
- data/spec/collector/block_spec.rb +33 -0
- data/spec/collector/options_spec.rb +211 -0
- data/spec/collector/watcher_spec.rb +180 -0
- data/spec/extensions/chewy_spec.rb +280 -78
- data/spec/sidekiq_spec.rb +38 -58
- data/spec/spec_helper.rb +27 -2
- data/spec/tantot_spec.rb +0 -370
- metadata +19 -15
- data/lib/tantot/collector.rb +0 -70
- data/lib/tantot/collector/base.rb +0 -46
- data/lib/tantot/collector/block.rb +0 -69
- data/lib/tantot/collector/watcher.rb +0 -67
- data/lib/tantot/formatter.rb +0 -10
- data/lib/tantot/formatter/compact.rb +0 -9
- data/lib/tantot/formatter/detailed.rb +0 -9
- data/lib/tantot/performer.rb +0 -24
- data/lib/tantot/performer/chewy.rb +0 -31
- data/lib/tantot/performer/inline.rb +0 -9
- data/lib/tantot/performer/sidekiq.rb +0 -21
- data/lib/tantot/registry.rb +0 -11
data/spec/sidekiq_spec.rb
CHANGED
@@ -3,15 +3,14 @@ require "spec_helper"
|
|
3
3
|
if defined?(::Sidekiq)
|
4
4
|
require 'sidekiq/testing'
|
5
5
|
|
6
|
-
describe Tantot::
|
6
|
+
describe Tantot::Strategy::Sidekiq do
|
7
7
|
around do |example|
|
8
|
-
Tantot.config.
|
8
|
+
Tantot.config.strategy = :sidekiq
|
9
9
|
example.run
|
10
|
-
Tantot.config.
|
10
|
+
Tantot.config.strategy = :inline
|
11
11
|
end
|
12
12
|
|
13
|
-
describe Tantot::
|
14
|
-
|
13
|
+
describe Tantot::Agent::Watcher do
|
15
14
|
class SidekiqWatcher
|
16
15
|
include Tantot::Watcher
|
17
16
|
|
@@ -22,28 +21,22 @@ if defined?(::Sidekiq)
|
|
22
21
|
before do
|
23
22
|
Sidekiq::Worker.clear_all
|
24
23
|
stub_model(:city) do
|
25
|
-
watch SidekiqWatcher, :name
|
24
|
+
watch SidekiqWatcher, only: :name
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
28
|
it "should call a sidekiq worker" do
|
30
|
-
Tantot.
|
29
|
+
Tantot.manager.run do
|
31
30
|
City.create name: 'foo'
|
32
31
|
end
|
33
|
-
expect(Tantot::
|
34
|
-
expect(Tantot::
|
35
|
-
expect(Tantot::
|
36
|
-
"model" => "City",
|
37
|
-
"attributes" => ["name"],
|
38
|
-
"options" => {},
|
39
|
-
"watcher" => "SidekiqWatcher",
|
40
|
-
"collector_class" => "Tantot::Collector::Watcher"},
|
41
|
-
{"City" => {"1" => {"name" => [nil, 'foo']}}}])
|
32
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(1)
|
33
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
|
34
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["args"][1]).to eq({"City" => {"1" => {"name" => [nil, 'foo']}}})
|
42
35
|
end
|
43
36
|
|
44
37
|
it "should call the watcher" do
|
45
38
|
::Sidekiq::Testing.inline! do
|
46
|
-
Tantot.
|
39
|
+
Tantot.manager.run do
|
47
40
|
city = City.create name: 'foo'
|
48
41
|
expect_any_instance_of(SidekiqWatcher).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
49
42
|
end
|
@@ -52,54 +45,48 @@ if defined?(::Sidekiq)
|
|
52
45
|
|
53
46
|
it "should skip sidekiq and process atomically when `sweep`ing, then resume using sidekiq" do
|
54
47
|
Sidekiq::Testing.fake! do
|
55
|
-
Tantot.
|
48
|
+
Tantot.manager.run do
|
56
49
|
# Create a model, then sweep. It should have called perform wihtout triggering a sidekiq worker
|
57
50
|
city = City.create name: 'foo'
|
58
51
|
expect_any_instance_of(SidekiqWatcher).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
59
|
-
Tantot.
|
60
|
-
expect(Tantot::
|
52
|
+
Tantot.manager.sweep(:inline)
|
53
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(0)
|
61
54
|
|
62
55
|
# Further modifications should trigger through sidekiq when exiting the strategy block
|
63
56
|
city.name = 'bar'
|
64
57
|
city.save
|
65
58
|
end
|
66
|
-
expect(Tantot::
|
67
|
-
expect(Tantot::
|
68
|
-
expect(Tantot::
|
69
|
-
"model" => "City",
|
70
|
-
"attributes" => ["name"],
|
71
|
-
"options" => {},
|
72
|
-
"watcher" => "SidekiqWatcher",
|
73
|
-
"collector_class" => "Tantot::Collector::Watcher"},
|
74
|
-
{"City" => {"1" => {"name" => ['foo', 'bar']}}}])
|
59
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(1)
|
60
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
|
61
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["args"][1]).to eq({"City" => {"1" => {"name" => ['foo', 'bar']}}})
|
75
62
|
end
|
76
63
|
end
|
77
64
|
end
|
78
65
|
|
79
|
-
describe Tantot::
|
66
|
+
describe Tantot::Strategy::Sidekiq do
|
80
67
|
context "with a specific queue on a watcher" do
|
81
|
-
|
82
|
-
|
83
|
-
include Tantot::Watcher
|
68
|
+
class SidekiqWatcherFooQueue
|
69
|
+
include Tantot::Watcher
|
84
70
|
|
85
|
-
|
71
|
+
watcher_options queue: :foo
|
86
72
|
|
87
|
-
|
88
|
-
end
|
73
|
+
def perform(changes)
|
89
74
|
end
|
75
|
+
end
|
90
76
|
|
77
|
+
before do
|
91
78
|
Sidekiq::Worker.clear_all
|
92
79
|
stub_model(:city) do
|
93
|
-
watch
|
80
|
+
watch SidekiqWatcherFooQueue, only: :name
|
94
81
|
end
|
95
82
|
end
|
96
83
|
|
97
84
|
it "should set the sidekiq queue accordingly" do
|
98
|
-
Tantot.
|
85
|
+
Tantot.manager.run do
|
99
86
|
City.create name: 'foo'
|
100
87
|
end
|
101
|
-
expect(Tantot::
|
102
|
-
expect(Tantot::
|
88
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(1)
|
89
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["queue"]).to eq('foo')
|
103
90
|
end
|
104
91
|
end
|
105
92
|
|
@@ -107,7 +94,7 @@ if defined?(::Sidekiq)
|
|
107
94
|
before do
|
108
95
|
Sidekiq::Worker.clear_all
|
109
96
|
stub_model(:city) do
|
110
|
-
watch(:name, queue: :foo) {|changes| }
|
97
|
+
watch(only: :name, queue: :foo) {|changes| }
|
111
98
|
end
|
112
99
|
end
|
113
100
|
|
@@ -116,16 +103,16 @@ if defined?(::Sidekiq)
|
|
116
103
|
watcher_options queue: :foo
|
117
104
|
end
|
118
105
|
|
119
|
-
Tantot.
|
106
|
+
Tantot.manager.run do
|
120
107
|
City.create name: 'foo'
|
121
108
|
end
|
122
|
-
expect(Tantot::
|
123
|
-
expect(Tantot::
|
109
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(1)
|
110
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["queue"]).to eq('foo')
|
124
111
|
end
|
125
112
|
end
|
126
113
|
end
|
127
114
|
|
128
|
-
describe Tantot::
|
115
|
+
describe Tantot::Agent::Block do
|
129
116
|
let(:value) { {changed: false} }
|
130
117
|
let(:changes) { {obj: nil} }
|
131
118
|
|
@@ -134,30 +121,23 @@ if defined?(::Sidekiq)
|
|
134
121
|
v = value
|
135
122
|
c = changes
|
136
123
|
stub_model(:city) do
|
137
|
-
watch(:name) {|changes| v[:changed] = true; c[:obj] = changes}
|
124
|
+
watch(only: :name) {|changes| v[:changed] = true; c[:obj] = changes}
|
138
125
|
end
|
139
126
|
end
|
140
127
|
|
141
128
|
it "should call a sidekiq worker" do
|
142
|
-
Tantot.
|
129
|
+
Tantot.manager.run do
|
143
130
|
City.create name: 'foo'
|
144
131
|
end
|
145
|
-
expect(Tantot::
|
146
|
-
|
147
|
-
expect(Tantot::
|
148
|
-
expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
|
149
|
-
"model" => "City",
|
150
|
-
"attributes" => ["name"],
|
151
|
-
"options" => {},
|
152
|
-
"block_id" => block_id,
|
153
|
-
"collector_class" => "Tantot::Collector::Block"},
|
154
|
-
{"1" => {"name" => [nil, 'foo']}}])
|
132
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.size).to eq(1)
|
133
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
|
134
|
+
expect(Tantot::Strategy::Sidekiq::Worker.jobs.first["args"][1]).to eq({"City" => {"1" => {"name" => [nil, 'foo']}}})
|
155
135
|
end
|
156
136
|
|
157
137
|
it "should call the watcher" do
|
158
138
|
::Sidekiq::Testing.inline! do
|
159
139
|
city = nil
|
160
|
-
Tantot.
|
140
|
+
Tantot.manager.run do
|
161
141
|
city = City.create name: 'foo'
|
162
142
|
end
|
163
143
|
expect(value[:changed]).to be_truthy
|
data/spec/spec_helper.rb
CHANGED
@@ -29,16 +29,41 @@ ActiveRecord::Schema.define do
|
|
29
29
|
t.column :name, :string
|
30
30
|
t.column :rating, :integer
|
31
31
|
end
|
32
|
+
|
33
|
+
create_table :streets do |t|
|
34
|
+
t.column :city_id, :integer
|
35
|
+
t.column :name, :string
|
36
|
+
end
|
37
|
+
|
38
|
+
create_table :users do |t|
|
39
|
+
t.column :username, :string
|
40
|
+
end
|
41
|
+
|
42
|
+
create_table :memberships do |t|
|
43
|
+
t.column :user_id, :integer
|
44
|
+
t.column :group_id, :integer
|
45
|
+
t.column :name, :string
|
46
|
+
end
|
47
|
+
|
48
|
+
create_table :groups do |t|
|
49
|
+
t.column :name, :string
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table :colors do |t|
|
53
|
+
t.column :group_id, :integer
|
54
|
+
t.column :name, :string
|
55
|
+
end
|
32
56
|
end
|
33
57
|
|
34
58
|
RSpec.configure do |config|
|
35
59
|
config.before(:suite) do
|
36
|
-
DatabaseCleaner.clean_with :
|
37
|
-
DatabaseCleaner.strategy = :
|
60
|
+
DatabaseCleaner.clean_with :truncation
|
61
|
+
DatabaseCleaner.strategy = :truncation
|
38
62
|
end
|
39
63
|
|
40
64
|
config.before do
|
41
65
|
DatabaseCleaner.start
|
66
|
+
Tantot.agent_registry.clear
|
42
67
|
end
|
43
68
|
|
44
69
|
config.after do
|
data/spec/tantot_spec.rb
CHANGED
@@ -4,374 +4,4 @@ describe Tantot do
|
|
4
4
|
it "has a version number" do
|
5
5
|
expect(Tantot::VERSION).not_to be nil
|
6
6
|
end
|
7
|
-
|
8
|
-
describe '.derive_watcher' do
|
9
|
-
class TestWatcher
|
10
|
-
include Tantot::Watcher
|
11
|
-
end
|
12
|
-
|
13
|
-
class WrongWatcher
|
14
|
-
end
|
15
|
-
|
16
|
-
module Foo
|
17
|
-
class BarWatcher
|
18
|
-
include Tantot::Watcher
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
specify { expect { described_class.derive_watcher('foo') }.to raise_error(Tantot::UnderivableWatcher) }
|
23
|
-
specify { expect { described_class.derive_watcher(WrongWatcher) }.to raise_error(Tantot::UnderivableWatcher) }
|
24
|
-
specify { expect(described_class.derive_watcher(TestWatcher)).to eq(TestWatcher) }
|
25
|
-
specify { expect(described_class.derive_watcher(Foo::BarWatcher)).to eq(Foo::BarWatcher) }
|
26
|
-
specify { expect(described_class.derive_watcher('test')).to eq(TestWatcher) }
|
27
|
-
specify { expect(described_class.derive_watcher('foo/bar')).to eq(Foo::BarWatcher) }
|
28
|
-
end
|
29
|
-
|
30
|
-
describe '.watch' do
|
31
|
-
|
32
|
-
let(:watcher_instance) { double }
|
33
|
-
|
34
|
-
before do
|
35
|
-
stub_class("TestWatcher") { include Tantot::Watcher }
|
36
|
-
allow(TestWatcher).to receive(:new).and_return(watcher_instance)
|
37
|
-
end
|
38
|
-
|
39
|
-
[true, false].each do |use_after_commit_callbacks|
|
40
|
-
context "using after_commit hooks: #{use_after_commit_callbacks}" do
|
41
|
-
before { allow(Tantot.config).to receive(:use_after_commit_callbacks).and_return(use_after_commit_callbacks) }
|
42
|
-
|
43
|
-
context "watching an attribute" do
|
44
|
-
before do
|
45
|
-
stub_model(:city) do
|
46
|
-
watch TestWatcher, :name
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
it "doesn't call back when the attribute doesn't change" do
|
51
|
-
Tantot.collector.run do
|
52
|
-
City.create
|
53
|
-
expect(watcher_instance).not_to receive(:perform)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
it "calls back when the attribute changes (on creation)" do
|
58
|
-
Tantot.collector.run do
|
59
|
-
city = City.create name: 'foo'
|
60
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
it "calls back on model update" do
|
65
|
-
city = City.create!
|
66
|
-
city.reload
|
67
|
-
Tantot.collector.sweep(:bypass)
|
68
|
-
|
69
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
70
|
-
Tantot.collector.run do
|
71
|
-
city.name = "foo"
|
72
|
-
city.save
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
it "calls back on model destroy" do
|
77
|
-
city = City.create!(name: 'foo')
|
78
|
-
city.reload
|
79
|
-
Tantot.collector.sweep(:bypass)
|
80
|
-
|
81
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['foo']}}}))
|
82
|
-
Tantot.collector.run do
|
83
|
-
city.destroy
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
it "calls back once per model even when updated more than once" do
|
88
|
-
Tantot.collector.run do
|
89
|
-
city = City.create! name: 'foo'
|
90
|
-
city.name = 'bar'
|
91
|
-
city.save
|
92
|
-
city.name = 'baz'
|
93
|
-
city.save
|
94
|
-
expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo', 'bar', 'baz']}}}))
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
it "allows to call a watcher mid-stream" do
|
99
|
-
Tantot.collector.run do
|
100
|
-
city = City.create name: 'foo'
|
101
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
102
|
-
Tantot.collector.sweep(:inline)
|
103
|
-
city.name = 'bar'
|
104
|
-
city.save
|
105
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['foo', 'bar']}}}))
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context "detailed format" do
|
113
|
-
let(:watcher_instance) { double }
|
114
|
-
before do
|
115
|
-
stub_class("DetailedTestWatcher") do
|
116
|
-
include Tantot::Watcher
|
117
|
-
|
118
|
-
watcher_options format: :detailed
|
119
|
-
end
|
120
|
-
allow(DetailedTestWatcher).to receive(:new).and_return(watcher_instance)
|
121
|
-
stub_model(:city) do
|
122
|
-
watch 'detailed_test', :name
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
it "should output a detailed array of changes" do
|
127
|
-
Tantot.collector.run do
|
128
|
-
city = City.create! name: 'foo'
|
129
|
-
city.name = 'bar'
|
130
|
-
city.save
|
131
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [[nil, 'foo'], ['foo', 'bar']]}}}))
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
context "on multiple models" do
|
137
|
-
before do
|
138
|
-
stub_model(:city) do
|
139
|
-
watch TestWatcher, :name, :country_id
|
140
|
-
end
|
141
|
-
stub_model(:country) do
|
142
|
-
watch TestWatcher, :country_code
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
it "calls back once per watch when multiple watched models change" do
|
147
|
-
country = Country.create!(country_code: "CDN")
|
148
|
-
city = City.create!(name: "Quebec", country_id: country.id)
|
149
|
-
country.reload
|
150
|
-
city.reload
|
151
|
-
Tantot.collector.sweep(:bypass)
|
152
|
-
|
153
|
-
expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['Quebec', 'foo', 'bar'], "country_id" => [country.id, nil]}}, Country => {country.id => {"country_code" => ['CDN', 'US']}}}))
|
154
|
-
Tantot.collector.run do
|
155
|
-
city.name = "foo"
|
156
|
-
city.save
|
157
|
-
city.name = "bar"
|
158
|
-
city.save
|
159
|
-
city.country_id = nil
|
160
|
-
city.save
|
161
|
-
country.country_code = 'US'
|
162
|
-
country.save
|
163
|
-
city.destroy
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
context "with multiple watchers" do
|
169
|
-
let(:watchA_instance) { double }
|
170
|
-
let(:watchB_instance) { double }
|
171
|
-
before do
|
172
|
-
stub_class("TestWatcherA") { include Tantot::Watcher }
|
173
|
-
stub_class("TestWatcherB") { include Tantot::Watcher }
|
174
|
-
allow(TestWatcherA).to receive(:new).and_return(watchA_instance)
|
175
|
-
allow(TestWatcherB).to receive(:new).and_return(watchB_instance)
|
176
|
-
stub_model(:city) do
|
177
|
-
watch TestWatcherA, :name, :country_id
|
178
|
-
watch TestWatcherB, :rating
|
179
|
-
end
|
180
|
-
stub_model(:country) do
|
181
|
-
watch TestWatcherA, :country_code
|
182
|
-
watch TestWatcherB, :name, :rating
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
it "calls each watcher once for multiple models" do
|
187
|
-
country = Country.create!(country_code: "CDN")
|
188
|
-
city = City.create!(name: "Quebec", country_id: country.id, rating: 12)
|
189
|
-
country.reload
|
190
|
-
city.reload
|
191
|
-
expect(watchA_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => ['Quebec', 'foo', 'bar'], "country_id" => [country.id, nil]}}, Country => {country.id => {"country_code" => ['CDN', 'US']}}}))
|
192
|
-
# WatchB receives the last value of rating since it has been destroyed
|
193
|
-
expect(watchB_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"rating" => [12]}}}))
|
194
|
-
Tantot.collector.sweep(:bypass)
|
195
|
-
|
196
|
-
Tantot.collector.run do
|
197
|
-
city.name = "foo"
|
198
|
-
city.save
|
199
|
-
city.name = "bar"
|
200
|
-
city.save
|
201
|
-
city.country_id = nil
|
202
|
-
city.save
|
203
|
-
country.country_code = 'US'
|
204
|
-
country.save
|
205
|
-
city.destroy
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
context 'watching all attributes' do
|
211
|
-
before do
|
212
|
-
stub_model(:city) do
|
213
|
-
watch TestWatcher
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should watch all changes" do
|
218
|
-
Tantot.collector.run do
|
219
|
-
city = City.create name: 'foo'
|
220
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {"id" => [nil, city.id], "name" => [nil, "foo"]}}}))
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should also watch on destroy, but when watching all attributes, change hash is empty" do
|
225
|
-
city = City.create!(name: 'foo')
|
226
|
-
city.reload
|
227
|
-
Tantot.collector.sweep(:bypass)
|
228
|
-
|
229
|
-
expect(watcher_instance).to receive(:perform).with(Tantot::Changes::ByModel.new({City => {city.id => {}}}))
|
230
|
-
Tantot.collector.run do
|
231
|
-
city.destroy
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
context 'with an additional `if` statement' do
|
237
|
-
|
238
|
-
[:no, :some].each do |attribute_opt|
|
239
|
-
context "with #{attribute_opt.to_s} attributes" do
|
240
|
-
let(:condition) { double }
|
241
|
-
before do
|
242
|
-
c = condition
|
243
|
-
watch_params = [TestWatcher]
|
244
|
-
watch_params << :id if attribute_opt == :some
|
245
|
-
watch_params << {if: -> { c.passed? }}
|
246
|
-
stub_model(:city) do
|
247
|
-
watch(*watch_params)
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
it "should fail if the condition is false" do
|
252
|
-
Tantot.collector.run do
|
253
|
-
expect(condition).to receive(:passed?).once.and_return(false)
|
254
|
-
City.create!
|
255
|
-
expect(watcher_instance).not_to receive(:perform)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
it "should pass if the condition is true" do
|
260
|
-
Tantot.collector.run do
|
261
|
-
expect(condition).to receive(:passed?).once.and_return(true)
|
262
|
-
City.create!
|
263
|
-
expect(watcher_instance).to receive(:perform)
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
context 'using a block' do
|
271
|
-
let(:value) { {changes: 0} }
|
272
|
-
let(:changes) { {obj: nil} }
|
273
|
-
before do
|
274
|
-
v = value
|
275
|
-
c = changes
|
276
|
-
stub_model(:city) do
|
277
|
-
watch {|changes| v[:changes] += 1; c[:obj] = changes}
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
it "should call the block" do
|
282
|
-
city = nil
|
283
|
-
Tantot.collector.run do
|
284
|
-
city = City.create!
|
285
|
-
end
|
286
|
-
expect(value[:changes]).to eq(1)
|
287
|
-
expect(changes[:obj]).to eq(Tantot::Changes::ById.new({city.id => {"id" => [nil, 1]}}))
|
288
|
-
end
|
289
|
-
|
290
|
-
it "call a single time if multiple changes occur" do
|
291
|
-
Tantot.collector.run do
|
292
|
-
3.times { City.create! }
|
293
|
-
end
|
294
|
-
expect(value[:changes]).to eq(1)
|
295
|
-
expect(changes[:obj]).to eq(Tantot::Changes::ById.new({1=>{"id"=>[nil, 1]}, 2=>{"id"=>[nil, 2]}, 3=>{"id"=>[nil, 3]}}))
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
context 'on:' do
|
300
|
-
|
301
|
-
context ':create' do
|
302
|
-
before do
|
303
|
-
stub_model(:city) do
|
304
|
-
watch TestWatcher, on: :create
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
it "should only watch creation" do
|
309
|
-
city = nil
|
310
|
-
Tantot.collector.run do
|
311
|
-
city = City.create!
|
312
|
-
expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"id" => [nil, city.id]}}}))
|
313
|
-
end
|
314
|
-
Tantot.collector.run do
|
315
|
-
city = City.find(city)
|
316
|
-
city.name = 'foo'
|
317
|
-
city.save
|
318
|
-
end
|
319
|
-
Tantot.collector.run do
|
320
|
-
city = City.find(city)
|
321
|
-
city.destroy
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
context ':update' do
|
327
|
-
before do
|
328
|
-
stub_model(:city) do
|
329
|
-
watch TestWatcher, on: :update
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
it "should only watch update" do
|
334
|
-
city = nil
|
335
|
-
Tantot.collector.run do
|
336
|
-
city = City.create!
|
337
|
-
expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {"name" => [nil, 'foo']}}}))
|
338
|
-
end
|
339
|
-
Tantot.collector.run do
|
340
|
-
city = City.find(city)
|
341
|
-
city.name = 'foo'
|
342
|
-
city.save
|
343
|
-
end
|
344
|
-
Tantot.collector.run do
|
345
|
-
city = City.find(city)
|
346
|
-
city.destroy
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
context ':destroy' do
|
352
|
-
before do
|
353
|
-
stub_model(:city) do
|
354
|
-
watch TestWatcher, on: :destroy
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
it "should only watch destruction" do
|
359
|
-
city = nil
|
360
|
-
Tantot.collector.run do
|
361
|
-
city = City.create!
|
362
|
-
expect(watcher_instance).to receive(:perform).once.with(Tantot::Changes::ByModel.new({City => {city.id => {}}}))
|
363
|
-
end
|
364
|
-
Tantot.collector.run do
|
365
|
-
city = City.find(city)
|
366
|
-
city.name = 'foo'
|
367
|
-
city.save
|
368
|
-
end
|
369
|
-
Tantot.collector.run do
|
370
|
-
city = City.find(city)
|
371
|
-
city.destroy
|
372
|
-
end
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
end # describe '.watch'
|
377
7
|
end
|