honeybadger 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/Gemfile +13 -0
  2. data/Gemfile.lock +114 -0
  3. data/Guardfile +5 -0
  4. data/MIT-LICENSE +22 -0
  5. data/README.md +271 -0
  6. data/Rakefile +261 -0
  7. data/SUPPORTED_RAILS_VERSIONS +26 -0
  8. data/TESTING.md +33 -0
  9. data/features/metal.feature +18 -0
  10. data/features/rack.feature +56 -0
  11. data/features/rails.feature +211 -0
  12. data/features/rake.feature +27 -0
  13. data/features/sinatra.feature +29 -0
  14. data/features/step_definitions/file_steps.rb +10 -0
  15. data/features/step_definitions/metal_steps.rb +23 -0
  16. data/features/step_definitions/rack_steps.rb +23 -0
  17. data/features/step_definitions/rails_application_steps.rb +394 -0
  18. data/features/step_definitions/rake_steps.rb +17 -0
  19. data/features/support/env.rb +17 -0
  20. data/features/support/honeybadger_shim.rb.template +8 -0
  21. data/features/support/rails.rb +201 -0
  22. data/features/support/rake/Rakefile +68 -0
  23. data/features/support/terminal.rb +107 -0
  24. data/generators/honeybadger/honeybadger_generator.rb +94 -0
  25. data/generators/honeybadger/lib/insert_commands.rb +34 -0
  26. data/generators/honeybadger/lib/rake_commands.rb +24 -0
  27. data/generators/honeybadger/templates/capistrano_hook.rb +6 -0
  28. data/generators/honeybadger/templates/honeybadger_tasks.rake +25 -0
  29. data/generators/honeybadger/templates/initializer.rb +6 -0
  30. data/honeybadger.gemspec +109 -0
  31. data/lib/honeybadger.rb +162 -0
  32. data/lib/honeybadger/backtrace.rb +123 -0
  33. data/lib/honeybadger/capistrano.rb +43 -0
  34. data/lib/honeybadger/configuration.rb +273 -0
  35. data/lib/honeybadger/notice.rb +314 -0
  36. data/lib/honeybadger/rack.rb +55 -0
  37. data/lib/honeybadger/rails.rb +34 -0
  38. data/lib/honeybadger/rails/action_controller_catcher.rb +30 -0
  39. data/lib/honeybadger/rails/controller_methods.rb +69 -0
  40. data/lib/honeybadger/rails/middleware/exceptions_catcher.rb +29 -0
  41. data/lib/honeybadger/rails3_tasks.rb +84 -0
  42. data/lib/honeybadger/railtie.rb +45 -0
  43. data/lib/honeybadger/rake_handler.rb +65 -0
  44. data/lib/honeybadger/sender.rb +120 -0
  45. data/lib/honeybadger/shared_tasks.rb +36 -0
  46. data/lib/honeybadger/tasks.rb +82 -0
  47. data/lib/honeybadger_tasks.rb +65 -0
  48. data/lib/rails/generators/honeybadger/honeybadger_generator.rb +99 -0
  49. data/rails/init.rb +1 -0
  50. data/resources/README.md +34 -0
  51. data/resources/ca-bundle.crt +3376 -0
  52. data/script/integration_test.rb +38 -0
  53. data/test/test_helper.rb +143 -0
  54. data/test/unit/backtrace_test.rb +180 -0
  55. data/test/unit/capistrano_test.rb +34 -0
  56. data/test/unit/configuration_test.rb +201 -0
  57. data/test/unit/honeybadger_tasks_test.rb +163 -0
  58. data/test/unit/logger_test.rb +72 -0
  59. data/test/unit/notice_test.rb +406 -0
  60. data/test/unit/notifier_test.rb +245 -0
  61. data/test/unit/rack_test.rb +56 -0
  62. data/test/unit/rails/action_controller_catcher_test.rb +300 -0
  63. data/test/unit/rails_test.rb +35 -0
  64. data/test/unit/sender_test.rb +257 -0
  65. metadata +315 -0
@@ -0,0 +1,245 @@
1
+ require 'test_helper'
2
+
3
+ class NotifierTest < Honeybadger::UnitTest
4
+ class OriginalException < Exception
5
+ end
6
+
7
+ class ContinuedException < Exception
8
+ end
9
+
10
+ include DefinesConstants
11
+
12
+ def setup
13
+ super
14
+ reset_config
15
+ end
16
+
17
+ def assert_sent(notice, notice_args)
18
+ assert_received(Honeybadger::Notice, :new) {|expect| expect.with(has_entries(notice_args)) }
19
+ assert_received(notice, :to_json)
20
+ assert_received(Honeybadger.sender, :send_to_honeybadger) {|expect| expect.with(notice.to_json) }
21
+ end
22
+
23
+ def set_public_env
24
+ Honeybadger.configure { |config| config.environment_name = 'production' }
25
+ end
26
+
27
+ def set_development_env
28
+ Honeybadger.configure { |config| config.environment_name = 'development' }
29
+ end
30
+
31
+ should "yield and save a configuration when configuring" do
32
+ yielded_configuration = nil
33
+ Honeybadger.configure do |config|
34
+ yielded_configuration = config
35
+ end
36
+
37
+ assert_kind_of Honeybadger::Configuration, yielded_configuration
38
+ assert_equal yielded_configuration, Honeybadger.configuration
39
+ end
40
+
41
+ should "not remove existing config options when configuring twice" do
42
+ first_config = nil
43
+ Honeybadger.configure do |config|
44
+ first_config = config
45
+ end
46
+ Honeybadger.configure do |config|
47
+ assert_equal first_config, config
48
+ end
49
+ end
50
+
51
+ should "configure the sender" do
52
+ sender = stub_sender
53
+ Honeybadger::Sender.stubs(:new => sender)
54
+ configuration = nil
55
+
56
+ Honeybadger.configure { |yielded_config| configuration = yielded_config }
57
+
58
+ assert_received(Honeybadger::Sender, :new) { |expect| expect.with(configuration) }
59
+ assert_equal sender, Honeybadger.sender
60
+ end
61
+
62
+ should "create and send a notice for an exception" do
63
+ set_public_env
64
+ exception = build_exception
65
+ stub_sender!
66
+ notice = stub_notice!
67
+
68
+ Honeybadger.notify(exception)
69
+
70
+ assert_sent notice, :exception => exception
71
+ end
72
+
73
+ should "create and send a notice for a hash" do
74
+ set_public_env
75
+ notice = stub_notice!
76
+ notice_args = { :error_message => 'uh oh' }
77
+ stub_sender!
78
+
79
+ Honeybadger.notify(notice_args)
80
+
81
+ assert_sent(notice, notice_args)
82
+ end
83
+
84
+ should "not pass the hash as an exception when sending a notice for it" do
85
+ set_public_env
86
+ notice = stub_notice!
87
+ notice_args = { :error_message => 'uh oh' }
88
+ stub_sender!
89
+
90
+ Honeybadger.notify(notice_args)
91
+
92
+ assert_received(Honeybadger::Notice, :new) {|expect| expect.with(Not(has_key(:exception))) }
93
+ end
94
+
95
+ should "create and send a notice for an exception that responds to to_hash" do
96
+ set_public_env
97
+ exception = build_exception
98
+ notice = stub_notice!
99
+ notice_args = { :error_message => 'uh oh' }
100
+ exception.stubs(:to_hash).returns(notice_args)
101
+ stub_sender!
102
+
103
+ Honeybadger.notify(exception)
104
+
105
+ assert_sent(notice, notice_args.merge(:exception => exception))
106
+ end
107
+
108
+ should "create and sent a notice for an exception and hash" do
109
+ set_public_env
110
+ exception = build_exception
111
+ notice = stub_notice!
112
+ notice_args = { :error_message => 'uh oh' }
113
+ stub_sender!
114
+
115
+ Honeybadger.notify(exception, notice_args)
116
+
117
+ assert_sent(notice, notice_args.merge(:exception => exception))
118
+ end
119
+
120
+ should "not create a notice in a development environment" do
121
+ set_development_env
122
+ sender = stub_sender!
123
+
124
+ Honeybadger.notify(build_exception)
125
+ Honeybadger.notify_or_ignore(build_exception)
126
+
127
+ assert_received(sender, :send_to_honeybadger) {|expect| expect.never }
128
+ end
129
+
130
+ should "not deliver an ignored exception when notifying implicitly" do
131
+ set_public_env
132
+ exception = build_exception
133
+ sender = stub_sender!
134
+ notice = stub_notice!
135
+ notice.stubs(:ignore? => true)
136
+
137
+ Honeybadger.notify_or_ignore(exception)
138
+
139
+ assert_received(sender, :send_to_honeybadger) {|expect| expect.never }
140
+ end
141
+
142
+ should "deliver an ignored exception when notifying manually" do
143
+ set_public_env
144
+ exception = build_exception
145
+ sender = stub_sender!
146
+ notice = stub_notice!
147
+ notice.stubs(:ignore? => true)
148
+
149
+ Honeybadger.notify(exception)
150
+
151
+ assert_sent(notice, :exception => exception)
152
+ end
153
+
154
+ should "pass config to created notices" do
155
+ exception = build_exception
156
+ config_opts = { 'one' => 'two', 'three' => 'four' }
157
+ notice = stub_notice!
158
+ stub_sender!
159
+ Honeybadger.configuration = stub('config', :merge => config_opts, :public? => true)
160
+
161
+ Honeybadger.notify(exception)
162
+
163
+ assert_received(Honeybadger::Notice, :new) do |expect|
164
+ expect.with(has_entries(config_opts))
165
+ end
166
+ end
167
+
168
+ context "building notice JSON for an exception" do
169
+ setup do
170
+ @params = { :controller => "users", :action => "create" }
171
+ @exception = build_exception
172
+ @hash = Honeybadger.build_lookup_hash_for(@exception, @params)
173
+ end
174
+
175
+ should "set action" do
176
+ assert_equal @params[:action], @hash[:action]
177
+ end
178
+
179
+ should "set controller" do
180
+ assert_equal @params[:controller], @hash[:component]
181
+ end
182
+
183
+ should "set line number" do
184
+ assert @hash[:line_number] =~ /\d+/
185
+ end
186
+
187
+ should "set file" do
188
+ assert_match /honeybadger\/rack_test\.rb$/, @hash[:file]
189
+ end
190
+
191
+ should "set rails_env to production" do
192
+ assert_equal 'production', @hash[:environment_name]
193
+ end
194
+
195
+ should "set error class" do
196
+ assert_equal @exception.class.to_s, @hash[:error_class]
197
+ end
198
+
199
+ should "not set file or line number with no backtrace" do
200
+ @exception.stubs(:backtrace).returns([])
201
+
202
+ @hash = Honeybadger.build_lookup_hash_for(@exception)
203
+
204
+ assert_nil @hash[:line_number]
205
+ assert_nil @hash[:file]
206
+ end
207
+
208
+ should "not set action or controller when not provided" do
209
+ @hash = Honeybadger.build_lookup_hash_for(@exception)
210
+
211
+ assert_nil @hash[:action]
212
+ assert_nil @hash[:controller]
213
+ end
214
+
215
+ context "when an exception that provides #original_exception is raised" do
216
+ setup do
217
+ @exception.stubs(:original_exception).returns(begin
218
+ raise NotifierTest::OriginalException.new
219
+ rescue Exception => e
220
+ e
221
+ end)
222
+ end
223
+
224
+ should "unwrap exceptions that provide #original_exception" do
225
+ @hash = Honeybadger.build_lookup_hash_for(@exception)
226
+ assert_equal "NotifierTest::OriginalException", @hash[:error_class]
227
+ end
228
+ end
229
+
230
+ context "when an exception that provides #continued_exception is raised" do
231
+ setup do
232
+ @exception.stubs(:continued_exception).returns(begin
233
+ raise NotifierTest::ContinuedException.new
234
+ rescue Exception => e
235
+ e
236
+ end)
237
+ end
238
+
239
+ should "unwrap exceptions that provide #continued_exception" do
240
+ @hash = Honeybadger.build_lookup_hash_for(@exception)
241
+ assert_equal "NotifierTest::ContinuedException", @hash[:error_class]
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,56 @@
1
+ require 'test_helper'
2
+
3
+ class RackTest < Honeybadger::UnitTest
4
+ should "call the upstream app with the environment" do
5
+ environment = { 'key' => 'value' }
6
+ app = lambda { |env| ['response', {}, env] }
7
+ stack = Honeybadger::Rack.new(app)
8
+
9
+ response = stack.call(environment)
10
+
11
+ assert_equal ['response', {}, environment], response
12
+ end
13
+
14
+ should "deliver an exception raised while calling an upstream app" do
15
+ Honeybadger.stubs(:notify_or_ignore)
16
+
17
+ exception = build_exception
18
+ environment = { 'key' => 'value' }
19
+ app = lambda do |env|
20
+ raise exception
21
+ end
22
+
23
+ begin
24
+ stack = Honeybadger::Rack.new(app)
25
+ stack.call(environment)
26
+ rescue Exception => raised
27
+ assert_equal exception, raised
28
+ else
29
+ flunk "Didn't raise an exception"
30
+ end
31
+
32
+ assert_received(Honeybadger, :notify_or_ignore) do |expect|
33
+ expect.with(exception, :rack_env => environment)
34
+ end
35
+ end
36
+
37
+ should "deliver an exception in rack.exception" do
38
+ Honeybadger.stubs(:notify_or_ignore)
39
+ exception = build_exception
40
+ environment = { 'key' => 'value' }
41
+
42
+ response = [200, {}, ['okay']]
43
+ app = lambda do |env|
44
+ env['rack.exception'] = exception
45
+ response
46
+ end
47
+ stack = Honeybadger::Rack.new(app)
48
+
49
+ actual_response = stack.call(environment)
50
+
51
+ assert_equal response, actual_response
52
+ assert_received(Honeybadger, :notify_or_ignore) do |expect|
53
+ expect.with(exception, :rack_env => environment)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,300 @@
1
+ require 'test_helper'
2
+ require 'honeybadger/rails'
3
+
4
+ class ActionControllerCatcherTest < Honeybadger::UnitTest
5
+ include DefinesConstants
6
+
7
+ def setup
8
+ super
9
+ reset_config
10
+ Honeybadger.sender = CollectingSender.new
11
+ define_constant('RAILS_ROOT', '/path/to/rails/root')
12
+ end
13
+
14
+ def ignore(exception_class)
15
+ Honeybadger.configuration.ignore << exception_class
16
+ end
17
+
18
+ def build_controller_class(&definition)
19
+ Class.new(ActionController::Base).tap do |klass|
20
+ klass.__send__(:include, Honeybadger::Rails::ActionControllerCatcher)
21
+ klass.class_eval(&definition) if definition
22
+ define_constant('HoneybadgerTestController', klass)
23
+ end
24
+ end
25
+
26
+ def assert_sent_hash(hash, &block)
27
+ hash.each do |key, value|
28
+ next if key.match(/^honeybadger\./) # We added this key.
29
+
30
+ new_block = Proc.new {
31
+ block.call(last_sent_notice_payload)[key]
32
+ }
33
+
34
+ if value.respond_to?(:to_hash)
35
+ assert_sent_hash(value.to_hash, &new_block)
36
+ else
37
+ assert_sent_element(value, &new_block)
38
+ end
39
+ end
40
+ end
41
+
42
+ def assert_sent_element(value, &block)
43
+ assert_equal yield(last_sent_notice_payload), stringify_array_elements(value)
44
+ end
45
+
46
+ def stringify_array_elements(data)
47
+ if data.is_a?(Array)
48
+ data.collect do |value|
49
+ stringify_array_elements(value)
50
+ end
51
+ else
52
+ data.to_s
53
+ end
54
+ end
55
+
56
+ def assert_sent_request_info_for(request)
57
+ params = request.parameters.to_hash
58
+ assert_sent_hash(params) { |h| h['request']['params'] }
59
+ assert_sent_element(params['controller']) { |h| h['request']['component'] }
60
+ assert_sent_element(params['action']) { |h| h['request']['action'] }
61
+ assert_sent_element(url_from_request(request)) { |h| h['request']['url'] }
62
+ assert_sent_hash(request.env) { |h| h['request']['cgi_data'] }
63
+ end
64
+
65
+ def url_from_request(request)
66
+ url = "#{request.protocol}#{request.host}"
67
+
68
+ unless [80, 443].include?(request.port)
69
+ url << ":#{request.port}"
70
+ end
71
+
72
+ url << request.request_uri
73
+ url
74
+ end
75
+
76
+ def sender
77
+ Honeybadger.sender
78
+ end
79
+
80
+ def last_sent_notice_json
81
+ sender.collected.last
82
+ end
83
+
84
+ def last_sent_notice_payload
85
+ assert_not_nil xml = last_sent_notice_json, "No json was sent"
86
+ JSON.parse(last_sent_notice_json)
87
+ end
88
+
89
+ def process_action(opts = {}, &action)
90
+ opts[:request] ||= ActionController::TestRequest.new
91
+ opts[:response] ||= ActionController::TestResponse.new
92
+ klass = build_controller_class do
93
+ cattr_accessor :local
94
+ define_method(:index, &action)
95
+ def local_request?
96
+ local
97
+ end
98
+ end
99
+ if opts[:filters]
100
+ klass.filter_parameter_logging *opts[:filters]
101
+ end
102
+ if opts[:user_agent]
103
+ if opts[:request].respond_to?(:user_agent=)
104
+ opts[:request].user_agent = opts[:user_agent]
105
+ else
106
+ opts[:request].env["HTTP_USER_AGENT"] = opts[:user_agent]
107
+ end
108
+ end
109
+ if opts[:port]
110
+ opts[:request].port = opts[:port]
111
+ end
112
+ klass.consider_all_requests_local = opts[:all_local]
113
+ klass.local = opts[:local]
114
+ controller = klass.new
115
+ controller.stubs(:rescue_action_in_public_without_honeybadger)
116
+ opts[:request].query_parameters = opts[:request].query_parameters.merge(opts[:params] || {})
117
+ opts[:request].session = ActionController::TestSession.new(opts[:session] || {})
118
+ # Prevents request.fullpath from crashing Rails in tests
119
+ opts[:request].env['REQUEST_URI'] = opts[:request].request_uri
120
+ controller.process(opts[:request], opts[:response])
121
+ controller
122
+ end
123
+
124
+ def process_action_with_manual_notification(args = {})
125
+ process_action(args) do
126
+ notify_honeybadger(:error_message => 'fail')
127
+ # Rails will raise a template error if we don't render something
128
+ render :nothing => true
129
+ end
130
+ end
131
+
132
+ def process_action_with_automatic_notification(args = {})
133
+ process_action(args) { raise "Hello" }
134
+ end
135
+
136
+ should "deliver notices from exceptions raised in public requests" do
137
+ process_action_with_automatic_notification
138
+ assert_caught_and_sent
139
+ end
140
+
141
+ should "not deliver notices from exceptions in local requests" do
142
+ process_action_with_automatic_notification(:local => true)
143
+ assert_caught_and_not_sent
144
+ end
145
+
146
+ should "not deliver notices from exceptions when all requests are local" do
147
+ process_action_with_automatic_notification(:all_local => true)
148
+ assert_caught_and_not_sent
149
+ end
150
+
151
+ should "not deliver notices from actions that don't raise" do
152
+ controller = process_action { render :text => 'Hello' }
153
+ assert_caught_and_not_sent
154
+ assert_equal 'Hello', controller.response.body
155
+ end
156
+
157
+ should "not deliver ignored exceptions raised by actions" do
158
+ ignore(RuntimeError)
159
+ process_action_with_automatic_notification
160
+ assert_caught_and_not_sent
161
+ end
162
+
163
+ should "deliver ignored exception raised manually" do
164
+ ignore(RuntimeError)
165
+ process_action_with_manual_notification
166
+ assert_caught_and_sent
167
+ end
168
+
169
+ should "deliver manually sent notices in public requests" do
170
+ process_action_with_manual_notification
171
+ assert_caught_and_sent
172
+ end
173
+
174
+ should "not deliver manually sent notices in local requests" do
175
+ process_action_with_manual_notification(:local => true)
176
+ assert_caught_and_not_sent
177
+ end
178
+
179
+ should "not deliver manually sent notices when all requests are local" do
180
+ process_action_with_manual_notification(:all_local => true)
181
+ assert_caught_and_not_sent
182
+ end
183
+
184
+ should "continue with default behavior after delivering an exception" do
185
+ controller = process_action_with_automatic_notification(:public => true)
186
+ # TODO: can we test this without stubbing?
187
+ assert_received(controller, :rescue_action_in_public_without_honeybadger)
188
+ end
189
+
190
+ should "not create actions from Honeybadger methods" do
191
+ controller = build_controller_class.new
192
+ assert_equal [], Honeybadger::Rails::ActionControllerCatcher.instance_methods
193
+ end
194
+
195
+ should "ignore exceptions when user agent is being ignored by regular expression" do
196
+ Honeybadger.configuration.ignore_user_agent_only = [/Ignored/]
197
+ process_action_with_automatic_notification(:user_agent => 'ShouldBeIgnored')
198
+ assert_caught_and_not_sent
199
+ end
200
+
201
+ should "ignore exceptions when user agent is being ignored by string" do
202
+ Honeybadger.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
203
+ process_action_with_automatic_notification(:user_agent => 'IgnoredUserAgent')
204
+ assert_caught_and_not_sent
205
+ end
206
+
207
+ should "not ignore exceptions when user agent is not being ignored" do
208
+ Honeybadger.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
209
+ process_action_with_automatic_notification(:user_agent => 'NonIgnoredAgent')
210
+ assert_caught_and_sent
211
+ end
212
+
213
+ should "send session data for manual notifications" do
214
+ data = { 'one' => 'two' }
215
+ process_action_with_manual_notification(:session => data)
216
+ assert_sent_hash(data) { |h| h['request']['session'] }
217
+ end
218
+
219
+ should "send session data for automatic notification" do
220
+ data = { 'one' => 'two' }
221
+ process_action_with_automatic_notification(:session => data)
222
+ assert_sent_hash(data) { |h| h['request']['session'] }
223
+ end
224
+
225
+ should "send request data for manual notification" do
226
+ params = { 'controller' => "honeybadger_test", 'action' => "index" }
227
+ controller = process_action_with_manual_notification(:params => params)
228
+ assert_sent_request_info_for controller.request
229
+ end
230
+
231
+ should "send request data for manual notification with non-standard port" do
232
+ params = { 'controller' => "honeybadger_test", 'action' => "index" }
233
+ controller = process_action_with_manual_notification(:params => params, :port => 81)
234
+ assert_sent_request_info_for controller.request
235
+ end
236
+
237
+ should "send request data for automatic notification" do
238
+ params = { 'controller' => "honeybadger_test", 'action' => "index" }
239
+ controller = process_action_with_automatic_notification(:params => params)
240
+ assert_sent_request_info_for controller.request
241
+ end
242
+
243
+ should "send request data for automatic notification with non-standard port" do
244
+ params = { 'controller' => "honeybadger_test", 'action' => "index" }
245
+ controller = process_action_with_automatic_notification(:params => params, :port => 81)
246
+ assert_sent_request_info_for controller.request
247
+ end
248
+
249
+ should "use standard rails logging filters on params and session and env" do
250
+ filtered_params = { "abc" => "123",
251
+ "def" => "456",
252
+ "ghi" => "[FILTERED]" }
253
+ filtered_session = { "abc" => "123",
254
+ "ghi" => "[FILTERED]" }
255
+ ENV['ghi'] = 'abc'
256
+ filtered_env = { 'ghi' => '[FILTERED]' }
257
+ filtered_cgi = { 'REQUEST_METHOD' => '[FILTERED]' }
258
+
259
+ process_action_with_automatic_notification(:filters => [:ghi, :request_method],
260
+ :params => { "abc" => "123",
261
+ "def" => "456",
262
+ "ghi" => "789" },
263
+ :session => { "abc" => "123",
264
+ "ghi" => "789" })
265
+ assert_sent_hash(filtered_params) { |h| h['request']['params'] }
266
+ assert_sent_hash(filtered_cgi) { |h| h['request']['cgi_data'] }
267
+ assert_sent_hash(filtered_session) { |h| h['request']['session'] }
268
+ end
269
+
270
+ should "call session.to_hash if available" do
271
+ hash_data = {:key => :value}
272
+
273
+ session = ActionController::TestSession.new
274
+ ActionController::TestSession.stubs(:new).returns(session)
275
+ session.stubs(:to_hash).returns(hash_data)
276
+
277
+ process_action_with_automatic_notification
278
+ assert_received(session, :to_hash)
279
+ assert_received(session, :data) { |expect| expect.never }
280
+ assert_caught_and_sent
281
+ end
282
+
283
+ should "call session.data if session.to_hash is undefined" do
284
+ hash_data = {:key => :value}
285
+
286
+ session = ActionController::TestSession.new
287
+ ActionController::TestSession.stubs(:new).returns(session)
288
+ session.stubs(:data).returns(hash_data)
289
+ if session.respond_to?(:to_hash)
290
+ class << session
291
+ undef to_hash
292
+ end
293
+ end
294
+
295
+ process_action_with_automatic_notification
296
+ assert_received(session, :to_hash) { |expect| expect.never }
297
+ assert_received(session, :data) { |expect| expect.at_least_once }
298
+ assert_caught_and_sent
299
+ end
300
+ end