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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tantot.rb +7 -23
  3. data/lib/tantot/agent.rb +19 -0
  4. data/lib/tantot/agent/base.rb +71 -0
  5. data/lib/tantot/agent/block.rb +32 -0
  6. data/lib/tantot/agent/registry.rb +34 -0
  7. data/lib/tantot/agent/watcher.rb +46 -0
  8. data/lib/tantot/changes.rb +2 -3
  9. data/lib/tantot/config.rb +2 -2
  10. data/lib/tantot/errors.rb +6 -0
  11. data/lib/tantot/extensions/chewy.rb +66 -18
  12. data/lib/tantot/extensions/grape/middleware.rb +1 -1
  13. data/lib/tantot/manager.rb +31 -0
  14. data/lib/tantot/observe.rb +36 -31
  15. data/lib/tantot/railtie.rb +5 -0
  16. data/lib/tantot/strategy.rb +24 -0
  17. data/lib/tantot/{performer → strategy}/bypass.rb +2 -2
  18. data/lib/tantot/strategy/chewy.rb +33 -0
  19. data/lib/tantot/strategy/inline.rb +9 -0
  20. data/lib/tantot/strategy/sidekiq.rb +36 -0
  21. data/lib/tantot/version.rb +1 -1
  22. data/performance/profile.rb +12 -8
  23. data/spec/collector/block_spec.rb +33 -0
  24. data/spec/collector/options_spec.rb +211 -0
  25. data/spec/collector/watcher_spec.rb +180 -0
  26. data/spec/extensions/chewy_spec.rb +280 -78
  27. data/spec/sidekiq_spec.rb +38 -58
  28. data/spec/spec_helper.rb +27 -2
  29. data/spec/tantot_spec.rb +0 -370
  30. metadata +19 -15
  31. data/lib/tantot/collector.rb +0 -70
  32. data/lib/tantot/collector/base.rb +0 -46
  33. data/lib/tantot/collector/block.rb +0 -69
  34. data/lib/tantot/collector/watcher.rb +0 -67
  35. data/lib/tantot/formatter.rb +0 -10
  36. data/lib/tantot/formatter/compact.rb +0 -9
  37. data/lib/tantot/formatter/detailed.rb +0 -9
  38. data/lib/tantot/performer.rb +0 -24
  39. data/lib/tantot/performer/chewy.rb +0 -31
  40. data/lib/tantot/performer/inline.rb +0 -9
  41. data/lib/tantot/performer/sidekiq.rb +0 -21
  42. 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::Performer::Sidekiq do
6
+ describe Tantot::Strategy::Sidekiq do
7
7
  around do |example|
8
- Tantot.config.performer = :sidekiq
8
+ Tantot.config.strategy = :sidekiq
9
9
  example.run
10
- Tantot.config.performer = :inline
10
+ Tantot.config.strategy = :inline
11
11
  end
12
12
 
13
- describe Tantot::Collector::Watcher do
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.collector.run do
29
+ Tantot.manager.run do
31
30
  City.create name: 'foo'
32
31
  end
33
- expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
34
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
35
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
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.collector.run do
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.collector.run do
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.collector.sweep(:inline)
60
- expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(0)
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::Performer::Sidekiq::Worker.jobs.size).to eq(1)
67
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
68
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["args"]).to eq([{
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::Performer::Sidekiq do
66
+ describe Tantot::Strategy::Sidekiq do
80
67
  context "with a specific queue on a watcher" do
81
- before do
82
- class SidekiqWatcher
83
- include Tantot::Watcher
68
+ class SidekiqWatcherFooQueue
69
+ include Tantot::Watcher
84
70
 
85
- watcher_options queue: :foo
71
+ watcher_options queue: :foo
86
72
 
87
- def perform(changes)
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 SidekiqWatcher, :name
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.collector.run do
85
+ Tantot.manager.run do
99
86
  City.create name: 'foo'
100
87
  end
101
- expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
102
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["queue"]).to eq('foo')
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.collector.run do
106
+ Tantot.manager.run do
120
107
  City.create name: 'foo'
121
108
  end
122
- expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
123
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["queue"]).to eq('foo')
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::Collector::Block do
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.collector.run do
129
+ Tantot.manager.run do
143
130
  City.create name: 'foo'
144
131
  end
145
- expect(Tantot::Performer::Sidekiq::Worker.jobs.size).to eq(1)
146
- block_id = Tantot.registry.watch_config.keys.last
147
- expect(Tantot::Performer::Sidekiq::Worker.jobs.first["queue"]).to eq('default')
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.collector.run do
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 :transaction
37
- DatabaseCleaner.strategy = :transaction
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