click_session 0.0.1

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 (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +286 -0
  7. data/Rakefile +1 -0
  8. data/click_session.gemspec +36 -0
  9. data/lib/click_session/async.rb +45 -0
  10. data/lib/click_session/click_session_processor.rb +64 -0
  11. data/lib/click_session/configuration.rb +142 -0
  12. data/lib/click_session/exceptions.rb +12 -0
  13. data/lib/click_session/failure_status_reporter.rb +15 -0
  14. data/lib/click_session/notifier.rb +23 -0
  15. data/lib/click_session/response_serializer.rb +34 -0
  16. data/lib/click_session/s3_connection.rb +34 -0
  17. data/lib/click_session/s3_file_uploader.rb +24 -0
  18. data/lib/click_session/session_state.rb +64 -0
  19. data/lib/click_session/status_reporter.rb +81 -0
  20. data/lib/click_session/successful_status_reporter.rb +15 -0
  21. data/lib/click_session/sync.rb +76 -0
  22. data/lib/click_session/version.rb +3 -0
  23. data/lib/click_session/web_runner.rb +60 -0
  24. data/lib/click_session/web_runner_processor.rb +65 -0
  25. data/lib/click_session/webhook.rb +24 -0
  26. data/lib/click_session/webhook_model_serializer.rb +7 -0
  27. data/lib/click_session.rb +34 -0
  28. data/lib/generators/click_session/db/migration/create_session_states.rb +13 -0
  29. data/lib/generators/click_session/initializers/click_session.rb +4 -0
  30. data/lib/generators/click_session/install_generator.rb +54 -0
  31. data/lib/tasks/click_session.rake +52 -0
  32. data/spec/click_session/async_spec.rb +66 -0
  33. data/spec/click_session/click_session_processor_spec.rb +292 -0
  34. data/spec/click_session/configuration_spec.rb +168 -0
  35. data/spec/click_session/failure_status_reporter_spec.rb +87 -0
  36. data/spec/click_session/notifier_spec.rb +72 -0
  37. data/spec/click_session/response_serializer_spec.rb +50 -0
  38. data/spec/click_session/s3_file_uploader_spec.rb +24 -0
  39. data/spec/click_session/session_state_spec.rb +54 -0
  40. data/spec/click_session/status_reporter_spec.rb +199 -0
  41. data/spec/click_session/successful_status_reporter_spec.rb +85 -0
  42. data/spec/click_session/sync_spec.rb +259 -0
  43. data/spec/click_session/web_runner_processor_spec.rb +143 -0
  44. data/spec/click_session/web_runner_spec.rb +77 -0
  45. data/spec/click_session/webhook_spec.rb +75 -0
  46. data/spec/factories/test_unit_model_factory.rb +5 -0
  47. data/spec/spec_helper.rb +42 -0
  48. data/spec/support/click_session_runner.rb +5 -0
  49. data/spec/support/dummy_web_runner.rb +2 -0
  50. data/spec/support/schema.rb +16 -0
  51. data/spec/support/test_unit_model.rb +3 -0
  52. metadata +310 -0
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+ require "click_session/configuration"
3
+ require 'support/test_unit_model'
4
+
5
+ describe ClickSession::ResponseSerializer do
6
+ let(:session_state) { ClickSession::SessionState.create }
7
+
8
+ let(:model) {
9
+ create(:test_unit_model)
10
+ }
11
+
12
+ describe "#serialize_success" do
13
+ before do
14
+ mock_configuration_model_class_with(model)
15
+ end
16
+
17
+ context 'With the default serializer' do
18
+ it "returns success meta data with the model serialized" do
19
+ session_state.model = model
20
+ response_serializer = ClickSession::ResponseSerializer.new
21
+
22
+ response = response_serializer.serialize_success(session_state)
23
+
24
+ expect(response).to eql({
25
+ id: session_state.id,
26
+ status: {
27
+ success: true
28
+ },
29
+ data: model.as_json
30
+ })
31
+ end
32
+ end
33
+ end
34
+
35
+ describe "#serialize_failure" do
36
+ it "returns failure meta data and no serialized model" do
37
+ session_state.model = model
38
+ response_serializer = ClickSession::ResponseSerializer.new
39
+
40
+ response = response_serializer.serialize_failure(session_state)
41
+
42
+ expect(response).to eql({
43
+ id: session_state.id,
44
+ status: {
45
+ success: false
46
+ }
47
+ })
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+
3
+ describe ClickSession::S3FileUploader do
4
+ describe "#upload_file_from"
5
+ it "returns the full url to the uploaded file" do
6
+ file_name = "unit-identifier-123.png"
7
+ key = "unit_key"
8
+ secret = "unit_secret"
9
+ bucket = "unit_bucket_name"
10
+
11
+ s3_connection = ClickSession::S3Connection.new(
12
+ key,
13
+ secret,
14
+ bucket
15
+ )
16
+ allow(s3_connection).
17
+ to receive(:upload_from_filesystem_to_bucket)
18
+
19
+ uploader = ClickSession::S3FileUploader.new(s3_connection)
20
+ screenshot_url = uploader.upload_file(file_name)
21
+
22
+ expect(screenshot_url).to eql("https://s3.amazonaws.com/#{bucket}/#{file_name}")
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require "spec_helper"
2
+ require "click_session/configuration"
3
+ require 'support/test_unit_model'
4
+
5
+ describe ClickSession::SessionState do
6
+ let(:model) { create(:test_unit_model) }
7
+
8
+ it { should validate_presence_of(:model_record) }
9
+
10
+ describe "#webhook_attempt_failed" do
11
+ it "increments the number of attempts" do
12
+ execution_state = ClickSession::SessionState.new
13
+
14
+ execution_state.webhook_attempt_failed
15
+
16
+ expect(execution_state.webhook_attempts).to eql(1)
17
+ end
18
+ end
19
+
20
+ describe "#model" do
21
+ context 'When model_class has been configured' do
22
+ before do
23
+ mock_configuration_model_class_with(model)
24
+ end
25
+
26
+ context 'with id to the record' do
27
+ it "returns the active record for the configured model_name" do
28
+ session_state = ClickSession::SessionState.create(model: model.id)
29
+
30
+ expect(session_state.model).to be_a(TestUnitModel)
31
+ end
32
+ end
33
+
34
+ context 'with an actual active record class' do
35
+ it "returns the active record for the configured model_name" do
36
+ session_state = ClickSession::SessionState.create(model: model)
37
+
38
+ expect(session_state.model).to be_a(TestUnitModel)
39
+ end
40
+ end
41
+
42
+ context 'When model passed is new' do
43
+ it "saves the model along with the session state" do
44
+ allow(model).to receive(:save!)
45
+ allow(model).to receive(:new_record?).and_return(true)
46
+
47
+ session_state = ClickSession::SessionState.create(model: model)
48
+
49
+ expect(model).to have_received(:save!)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,199 @@
1
+ require "spec_helper"
2
+ require "click_session/configuration"
3
+ require 'support/test_unit_model'
4
+
5
+ describe ClickSession::StatusReporter do
6
+ describe "#report" do
7
+ let(:session_state) { build_session_state_in_processed_state }
8
+ let(:model) { create(:test_unit_model) }
9
+
10
+ before :each do
11
+ @notifier_stub = stub_notifier_in_configuration
12
+
13
+ mock_configuration_model_class_with(model)
14
+ end
15
+
16
+ context 'when the reporting endpoint is online' do
17
+ it "reports the successfull order back" do
18
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
19
+ ok_webhook_stub
20
+ )
21
+
22
+ expect { status_reporter.report(session_state) }.
23
+ not_to raise_error
24
+ end
25
+
26
+ it "changes the state to 'success_reported'" do
27
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
28
+ ok_webhook_stub
29
+ )
30
+
31
+ status_reporter.report(session_state)
32
+
33
+ expect(session_state.success_reported?).to eql(true)
34
+ end
35
+
36
+ it "notifies about the successful reporting" do
37
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
38
+ ok_webhook_stub
39
+ )
40
+
41
+ status_reporter.report(session_state)
42
+
43
+ expect(@notifier_stub).
44
+ to have_received(:session_reported).
45
+ with(session_state)
46
+ end
47
+
48
+ context 'with a serializer_class in the configuration' do
49
+ it "serializes the response with the user defined serializer" do
50
+ class MyDefinedSerializer < ClickSession::WebhookModelSerializer
51
+ def serialize(model)
52
+ {
53
+ user_defined: "Serializer"
54
+ }
55
+ end
56
+ end
57
+
58
+ serializer_double = double(MyDefinedSerializer)
59
+ serializer_stub = MyDefinedSerializer.new
60
+
61
+ # Add the stub to the double
62
+ allow(serializer_double).
63
+ to receive(:new).
64
+ and_return(serializer_stub)
65
+
66
+ # Make the configuration return our double
67
+ allow(ClickSession.configuration).
68
+ to receive(:serializer_class).
69
+ and_return(serializer_double)
70
+
71
+ webhook_stub = ClickSession::Webhook.new("a-unit-test-web-hook.url")
72
+ allow(webhook_stub).
73
+ to receive(:call)
74
+
75
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
76
+ webhook_stub
77
+ )
78
+
79
+ status_reporter.report(session_state)
80
+
81
+ expect(webhook_stub).
82
+ to have_received(:call).
83
+ with( {
84
+ id: session_state.id,
85
+ status: {
86
+ success: true
87
+ },
88
+ data:{
89
+ user_defined: "Serializer"
90
+ }
91
+ } )
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'when the reporting endpoint is offline' do
97
+ it "leaves the state in 'processed'" do
98
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
99
+ failing_webhook_stub
100
+ )
101
+
102
+ status_reporter.report(session_state)
103
+
104
+ expect(session_state.processed?).to eql(true)
105
+ end
106
+
107
+ it "notifies about the rescued error" do
108
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
109
+ failing_webhook_stub
110
+ )
111
+
112
+ status_reporter.report(session_state)
113
+
114
+ expect(@notifier_stub).to have_received(:rescued_error).once
115
+ end
116
+
117
+ context 'when the retry threshold has been reached' do
118
+ it "notifies the status_notifier about the threshold" do
119
+ session_state.webhook_attempts = 4
120
+
121
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
122
+ failing_webhook_threshold_reached_stub
123
+ )
124
+
125
+ status_reporter.report(session_state)
126
+
127
+ expect(@notifier_stub).to have_received(:rescued_error).once
128
+
129
+ expect(@notifier_stub).
130
+ to have_received(:session_failed_to_report).
131
+ with(session_state)
132
+ end
133
+ end
134
+ end
135
+
136
+ def ok_webhook_stub
137
+ unless @webhook
138
+ @webhook = ClickSession::Webhook.new("a-unit-test-web-hook.url")
139
+ expect(@webhook).
140
+ to receive(:call).
141
+ with(anything)
142
+ end
143
+ @webhook
144
+ end
145
+
146
+ def failing_webhook_stub
147
+ unless @webhook
148
+ @webhook = ClickSession::Webhook.new("a-unit-test-web-hook.url")
149
+ expect(@webhook).
150
+ to receive(:call).
151
+ with(anything).
152
+ and_raise(StandardError)
153
+ end
154
+ @webhook
155
+ end
156
+
157
+ def failing_webhook_threshold_reached_stub
158
+ unless @webhook
159
+ @webhook = ClickSession::Webhook.new("a-unit-test-web-hook.url")
160
+ expect(@webhook).
161
+ to receive(:call).
162
+ with(anything).
163
+ and_raise(StandardError)
164
+ end
165
+ @webhook
166
+ end
167
+
168
+ def stub_notifier_in_configuration
169
+ notifier_double = double(ClickSession::Notifier)
170
+ notifier_stub = ClickSession::Notifier.new
171
+
172
+ # Stub the method
173
+ allow(notifier_stub).
174
+ to receive(:session_failed_to_report)
175
+
176
+ allow(notifier_stub).
177
+ to receive(:session_reported)
178
+
179
+ allow(notifier_stub).
180
+ to receive(:rescued_error)
181
+
182
+ # Add the stub to the double
183
+ allow(notifier_double).
184
+ to receive(:new).
185
+ and_return(notifier_stub)
186
+
187
+ # Make the configuration return our double
188
+ allow(ClickSession.configuration).
189
+ to receive(:notifier_class).
190
+ and_return(notifier_double)
191
+
192
+ notifier_stub
193
+ end
194
+
195
+ def build_session_state_in_processed_state
196
+ ClickSession::SessionState.create(state: 1, model_record: model.id)
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,85 @@
1
+ require "spec_helper"
2
+ require "click_session/configuration"
3
+ require 'support/test_unit_model'
4
+
5
+ describe ClickSession::SuccessfulStatusReporter do
6
+ describe "#report" do
7
+ let(:model) { create(:test_unit_model) }
8
+
9
+ before do
10
+ stub_notifier_in_configuration
11
+ mock_configuration_model_class_with(model)
12
+ end
13
+
14
+ it "rejects shippings not processed" do
15
+ session_state = build_session_state_in_not_processed_state
16
+ status_reporter = ClickSession::SuccessfulStatusReporter.new
17
+
18
+ expect { status_reporter.report(session_state) }.
19
+ to raise_error(ArgumentError)
20
+ end
21
+
22
+ it "rejects shippings which have failed" do
23
+ session_state = build_session_state_in_failed_state
24
+ status_reporter = ClickSession::SuccessfulStatusReporter.new
25
+
26
+ expect { status_reporter.report(session_state) }.
27
+ to raise_error(ArgumentError)
28
+ end
29
+
30
+ it "reports with an OK status" do
31
+ session_state = build_session_state_in_processed_state
32
+ webhook_stub = ClickSession::Webhook.new("success.url")
33
+ allow(webhook_stub).to receive(:call)
34
+
35
+ status_reporter = ClickSession::SuccessfulStatusReporter.new(
36
+ webhook_stub
37
+ )
38
+
39
+ status_reporter.report(session_state)
40
+
41
+ expect(webhook_stub).
42
+ to have_received(:call).
43
+ with({
44
+ id: session_state.id,
45
+ status: {
46
+ success: true
47
+ },
48
+ data: session_state.model.as_json
49
+ })
50
+ end
51
+
52
+ def stub_notifier_in_configuration
53
+ notifier_double = class_double(ClickSession::Notifier)
54
+ notifier_stub = ClickSession::Notifier.new
55
+
56
+ # Stub the methods
57
+ allow(notifier_stub).
58
+ to receive(:session_reported)
59
+
60
+ # Add the stub to the double
61
+ allow(notifier_double).
62
+ to receive(:new).
63
+ and_return(notifier_stub)
64
+
65
+ # Make the configuration return our double
66
+ allow(ClickSession.configuration).
67
+ to receive(:notifier_class).
68
+ and_return(notifier_double)
69
+
70
+ notifier_stub
71
+ end
72
+
73
+ def build_session_state_in_not_processed_state
74
+ ClickSession::SessionState.create(state: 0, model_record: model.id)
75
+ end
76
+
77
+ def build_session_state_in_processed_state
78
+ ClickSession::SessionState.create(state: 1, model_record: model.id)
79
+ end
80
+
81
+ def build_session_state_in_failed_state
82
+ ClickSession::SessionState.create(state: 2, model_record: model.id)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,259 @@
1
+ require 'spec_helper'
2
+ require 'click_session/configuration'
3
+ require 'support/test_unit_model'
4
+
5
+ describe ClickSession::Sync do
6
+ describe "#run" do
7
+
8
+ let(:model) { create(:test_unit_model) }
9
+
10
+ before do
11
+ @notifier_stub = stub_notifier_in_configuration
12
+ mock_configuration_model_class_with(model)
13
+
14
+ processor_stub = ClickSession::WebRunner.new
15
+ mock_configuration_processor_class_with(processor_stub)
16
+ @web_runner_processor_stub = stub_web_runner_processor_with( processor_stub )
17
+ end
18
+
19
+ context 'when processing is successful' do
20
+ before :each do
21
+ click_session_processor_mock = mock_click_session_processor_with(
22
+ @web_runner_processor_stub,
23
+ @notifier_stub
24
+ )
25
+
26
+ expect_any_instance_of(ClickSession::SessionState).
27
+ to receive(:reported_back!)
28
+
29
+ disable_screenshots
30
+ end
31
+
32
+ it "saves the session_state" do
33
+ sync_click_session = ClickSession::Sync.new(model)
34
+
35
+ expect { sync_click_session.run }.
36
+ to change { ClickSession::SessionState.count }.by(1)
37
+ end
38
+
39
+ it "processes the session" do
40
+ sync_click_session = ClickSession::Sync.new(model)
41
+
42
+ sync_click_session.run
43
+
44
+ expect(ClickSession::ClickSessionProcessor).
45
+ to have_received(:new).
46
+ with(
47
+ ClickSession::SessionState,
48
+ @web_runner_processor_stub,
49
+ @notifier_stub,
50
+ anything
51
+ )
52
+ end
53
+
54
+ context 'with screenshot is enabled' do
55
+ it "passes the configuration on to the ClickSessionRunner" do
56
+ screenshot_configuration = {
57
+ s3_bucket: "unit-s3",
58
+ s3_key_id: "unit-s3-key",
59
+ s3_access_key: "unit_s3_access_key"
60
+ }
61
+
62
+ allow(ClickSession.configuration).
63
+ to receive(:screenshot_enabled?).
64
+ and_return(true)
65
+
66
+ allow(ClickSession.configuration).
67
+ to receive(:screenshot).
68
+ and_return(screenshot_configuration)
69
+
70
+ sync_click_session = ClickSession::Sync.new(model)
71
+
72
+ sync_click_session.run
73
+
74
+ expect(ClickSession::ClickSessionProcessor).
75
+ to have_received(:new).
76
+ with(
77
+ ClickSession::SessionState,
78
+ @web_runner_processor_stub,
79
+ @notifier_stub,
80
+ {
81
+ screenshot_enabled: true,
82
+ screenshot_options: screenshot_configuration
83
+ }
84
+ )
85
+ end
86
+ end
87
+
88
+ it "uses the web_runner and notifier from the configuration" do
89
+ sync_click_session = ClickSession::Sync.new(model)
90
+
91
+ sync_click_session.run
92
+
93
+ expect(ClickSession.configuration).to have_received(:notifier_class)
94
+ expect(ClickSession.configuration).to have_received(:processor_class)
95
+ end
96
+
97
+ it "changes the state of the click_session to 'success_reported'" do
98
+ sync_click_session = ClickSession::Sync.new(model)
99
+
100
+ sync_click_session.run
101
+
102
+ # Expectation is in the 'before' method
103
+ end
104
+
105
+ it "returns a serialized OK response with the model" do
106
+ sync_click_session = ClickSession::Sync.new(model)
107
+
108
+ response = sync_click_session.run
109
+
110
+ expect(response[:id]).to be_a(Integer)
111
+ expect(response[:status][:success]).to be(true)
112
+ expect(response[:data]).to eql(model.as_json)
113
+ end
114
+ end
115
+
116
+ context 'when processing fails' do
117
+ before :each do
118
+ mock_click_session_processor_and_raise_error(
119
+ @web_runner_processor_stub,
120
+ @notifier_stub
121
+ )
122
+
123
+ expect_any_instance_of(ClickSession::SessionState).
124
+ to receive(:reported_back!)
125
+
126
+ disable_screenshots
127
+ end
128
+
129
+ it "saves the session_state" do
130
+ sync_click_session = ClickSession::Sync.new(model)
131
+
132
+ expect { sync_click_session.run }.
133
+ to change { ClickSession::SessionState.count }.by(1)
134
+ end
135
+
136
+ it "returns a serialized FAIL response" do
137
+ sync_click_session = ClickSession::Sync.new(model)
138
+
139
+ response = sync_click_session.run
140
+
141
+ expect(response[:id]).to be_a(Integer)
142
+ expect(response[:status][:success]).to be(false)
143
+ expect(response[:data]).to be_nil
144
+ end
145
+
146
+ it "changes the state of the click_session to 'reported'" do
147
+ sync_click_session = ClickSession::Sync.new(model)
148
+
149
+ sync_click_session.run
150
+
151
+ # Expectation in the 'before do ...'
152
+ end
153
+ end
154
+ end
155
+
156
+ def mock_configuration_processor_class_with(processor_stub)
157
+ processor_double = class_double(ClickSession::WebRunner)
158
+ allow(processor_double).
159
+ to receive(:new).
160
+ and_return(processor_stub)
161
+
162
+ allow(ClickSession.configuration).
163
+ to receive(:processor_class).
164
+ and_return(processor_double)
165
+ end
166
+
167
+ def mock_configuration_notifier_class_with(notifier_mock)
168
+ notifier_double = class_double(ClickSession::Notifier)
169
+ allow(notifier_double).
170
+ to receive(:new).
171
+ and_return(notifier_mock)
172
+
173
+ allow(ClickSession.configuration).
174
+ to receive(:processor_class).
175
+ and_return(notifier_double)
176
+
177
+ notifier_mock
178
+ end
179
+
180
+ def disable_screenshots
181
+ allow(ClickSession.configuration).
182
+ to receive(:screenshot_enabled?).
183
+ and_return(false)
184
+ end
185
+
186
+
187
+ def stub_web_runner_processor_with(processor_stub)
188
+ web_runner_processor_stub = ClickSession::WebRunnerProcessor.new(processor_stub)
189
+
190
+ allow(web_runner_processor_stub).
191
+ to receive(:process).
192
+ with(model).
193
+ and_return(model)
194
+
195
+ allow(ClickSession::WebRunnerProcessor).
196
+ to receive(:new).
197
+ and_return(web_runner_processor_stub)
198
+
199
+ web_runner_processor_stub
200
+ end
201
+
202
+ def mock_click_session_processor_with(processor_stub, notifier_stub)
203
+ click_session_processor_mock = ClickSession::ClickSessionProcessor.new(
204
+ ClickSession::SessionState.new,
205
+ processor_stub,
206
+ notifier_stub
207
+ )
208
+
209
+ allow(click_session_processor_mock).
210
+ to receive(:process)
211
+
212
+ allow(ClickSession::ClickSessionProcessor).
213
+ to receive(:new).
214
+ and_return(click_session_processor_mock)
215
+ end
216
+
217
+ def mock_click_session_processor_and_raise_error(processor_stub, notifier_stub)
218
+ click_session_processor_mock = ClickSession::ClickSessionProcessor.new(
219
+ ClickSession::SessionState.new,
220
+ processor_stub,
221
+ notifier_stub
222
+ )
223
+
224
+ allow(click_session_processor_mock).
225
+ to receive(:process).
226
+ and_raise(ClickSession::TooManyRetriesError)
227
+
228
+ allow(ClickSession::ClickSessionProcessor).
229
+ to receive(:new).
230
+ and_return(click_session_processor_mock)
231
+ end
232
+
233
+ def stub_notifier_in_configuration
234
+ notifier_double = class_double(ClickSession::Notifier)
235
+ notifier_stub = ClickSession::Notifier.new
236
+
237
+ # Stub the methods
238
+ allow(notifier_stub).
239
+ to receive(:session_failed)
240
+
241
+ allow(notifier_stub).
242
+ to receive(:session_successful)
243
+
244
+ allow(notifier_stub).
245
+ to receive(:rescued_error)
246
+
247
+ # Add the stub to the double
248
+ allow(notifier_double).
249
+ to receive(:new).
250
+ and_return(notifier_stub)
251
+
252
+ # Make the configuration return our double
253
+ allow(ClickSession.configuration).
254
+ to receive(:notifier_class).
255
+ and_return(notifier_double)
256
+
257
+ notifier_stub
258
+ end
259
+ end