hoptoad_notifier 2.1.0

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.
@@ -0,0 +1,314 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class CatcherTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ def setup
8
+ super
9
+ reset_config
10
+ HoptoadNotifier.sender = CollectingSender.new
11
+ define_constant('RAILS_ROOT', '/path/to/rails/root')
12
+ end
13
+
14
+ def ignore(exception_class)
15
+ HoptoadNotifier.configuration.ignore << exception_class
16
+ end
17
+
18
+ def build_controller_class(&definition)
19
+ returning Class.new(ActionController::Base) do |klass|
20
+ klass.__send__(:include, HoptoadNotifier::Catcher)
21
+ klass.class_eval(&definition) if definition
22
+ define_constant('HoptoadTestController', klass)
23
+ end
24
+ end
25
+
26
+ def assert_sent_hash(hash, xpath)
27
+ hash.each do |key, value|
28
+ element_xpath = "#{xpath}/var[@key = '#{key}']"
29
+ if value.respond_to?(:to_hash)
30
+ assert_sent_hash value.to_hash, element_xpath
31
+ else
32
+ assert_sent_element value.to_s, element_xpath
33
+ end
34
+ end
35
+ end
36
+
37
+ def assert_sent_element(value, xpath)
38
+ assert_valid_node last_sent_notice_document, xpath, value
39
+ end
40
+
41
+ def assert_sent_request_info_for(request)
42
+ params = request.parameters.to_hash
43
+ assert_sent_hash params, '/notice/request/params'
44
+ assert_sent_element params['controller'], '/notice/request/component'
45
+ assert_sent_element params['action'], '/notice/request/action'
46
+ assert_sent_element url_from_request(request), '/notice/request/url'
47
+ assert_sent_hash request.env, '/notice/request/cgi-data'
48
+ end
49
+
50
+ def url_from_request(request)
51
+ url = "#{request.protocol}#{request.host}"
52
+
53
+ unless [80, 443].include?(request.port)
54
+ url << ":#{request.port}"
55
+ end
56
+
57
+ url << request.request_uri
58
+ url
59
+ end
60
+
61
+ def sender
62
+ HoptoadNotifier.sender
63
+ end
64
+
65
+ def last_sent_notice_xml
66
+ sender.collected.last
67
+ end
68
+
69
+ def last_sent_notice_document
70
+ assert_not_nil xml = last_sent_notice_xml, "No xml was sent"
71
+ Nokogiri::XML.parse(xml)
72
+ end
73
+
74
+ def process_action(opts = {}, &action)
75
+ opts[:request] ||= ActionController::TestRequest.new
76
+ opts[:response] ||= ActionController::TestResponse.new
77
+ klass = build_controller_class do
78
+ cattr_accessor :local
79
+ define_method(:index, &action)
80
+ def local_request?
81
+ local
82
+ end
83
+ end
84
+ if opts[:filters]
85
+ klass.filter_parameter_logging *opts[:filters]
86
+ end
87
+ if opts[:user_agent]
88
+ if opts[:request].respond_to?(:user_agent=)
89
+ opts[:request].user_agent = opts[:user_agent]
90
+ else
91
+ opts[:request].env["HTTP_USER_AGENT"] = opts[:user_agent]
92
+ end
93
+ end
94
+ if opts[:port]
95
+ opts[:request].port = opts[:port]
96
+ end
97
+ klass.consider_all_requests_local = opts[:all_local]
98
+ klass.local = opts[:local]
99
+ controller = klass.new
100
+ controller.stubs(:rescue_action_in_public_without_hoptoad)
101
+ opts[:request].query_parameters = opts[:request].query_parameters.merge(opts[:params] || {})
102
+ opts[:request].session = ActionController::TestSession.new(opts[:session] || {})
103
+ controller.process(opts[:request], opts[:response])
104
+ controller
105
+ end
106
+
107
+ def process_action_with_manual_notification(args = {})
108
+ process_action(args) do
109
+ notify_hoptoad(:error_message => 'fail')
110
+ # Rails will raise a template error if we don't render something
111
+ render :nothing => true
112
+ end
113
+ end
114
+
115
+ def process_action_with_automatic_notification(args = {})
116
+ process_action(args) { raise "Hello" }
117
+ end
118
+
119
+ should "deliver notices from exceptions raised in public requests" do
120
+ process_action_with_automatic_notification
121
+ assert_caught_and_sent
122
+ end
123
+
124
+ should "not deliver notices from exceptions in local requests" do
125
+ process_action_with_automatic_notification(:local => true)
126
+ assert_caught_and_not_sent
127
+ end
128
+
129
+ should "not deliver notices from exceptions when all requests are local" do
130
+ process_action_with_automatic_notification(:all_local => true)
131
+ assert_caught_and_not_sent
132
+ end
133
+
134
+ should "not deliver notices from actions that don't raise" do
135
+ controller = process_action { render :text => 'Hello' }
136
+ assert_caught_and_not_sent
137
+ assert_equal 'Hello', controller.response.body
138
+ end
139
+
140
+ should "not deliver ignored exceptions raised by actions" do
141
+ ignore(RuntimeError)
142
+ process_action_with_automatic_notification
143
+ assert_caught_and_not_sent
144
+ end
145
+
146
+ should "deliver ignored exception raised manually" do
147
+ ignore(RuntimeError)
148
+ process_action_with_manual_notification
149
+ assert_caught_and_sent
150
+ end
151
+
152
+ should "deliver manually sent notices in public requests" do
153
+ process_action_with_manual_notification
154
+ assert_caught_and_sent
155
+ end
156
+
157
+ should "not deliver manually sent notices in local requests" do
158
+ process_action_with_manual_notification(:local => true)
159
+ assert_caught_and_not_sent
160
+ end
161
+
162
+ should "not deliver manually sent notices when all requests are local" do
163
+ process_action_with_manual_notification(:all_local => true)
164
+ assert_caught_and_not_sent
165
+ end
166
+
167
+ should "continue with default behavior after delivering an exception" do
168
+ controller = process_action_with_automatic_notification(:public => true)
169
+ # TODO: can we test this without stubbing?
170
+ assert_received(controller, :rescue_action_in_public_without_hoptoad)
171
+ end
172
+
173
+ should "not create actions from Hoptoad methods" do
174
+ controller = build_controller_class.new
175
+ assert_equal [], HoptoadNotifier::Catcher.instance_methods
176
+ end
177
+
178
+ should "ignore exceptions when user agent is being ignored by regular expression" do
179
+ HoptoadNotifier.configuration.ignore_user_agent_only = [/Ignored/]
180
+ process_action_with_automatic_notification(:user_agent => 'ShouldBeIgnored')
181
+ assert_caught_and_not_sent
182
+ end
183
+
184
+ should "ignore exceptions when user agent is being ignored by string" do
185
+ HoptoadNotifier.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
186
+ process_action_with_automatic_notification(:user_agent => 'IgnoredUserAgent')
187
+ assert_caught_and_not_sent
188
+ end
189
+
190
+ should "not ignore exceptions when user agent is not being ignored" do
191
+ HoptoadNotifier.configuration.ignore_user_agent_only = ['IgnoredUserAgent']
192
+ process_action_with_automatic_notification(:user_agent => 'NonIgnoredAgent')
193
+ assert_caught_and_sent
194
+ end
195
+
196
+ should "send session data for manual notifications" do
197
+ data = { 'one' => 'two' }
198
+ process_action_with_manual_notification(:session => data)
199
+ assert_sent_hash data, "/notice/request/session"
200
+ end
201
+
202
+ should "send session data for automatic notification" do
203
+ data = { 'one' => 'two' }
204
+ process_action_with_automatic_notification(:session => data)
205
+ assert_sent_hash data, "/notice/request/session"
206
+ end
207
+
208
+ should "send request data for manual notification" do
209
+ params = { 'controller' => "hoptoad_test", 'action' => "index" }
210
+ controller = process_action_with_manual_notification(:params => params)
211
+ assert_sent_request_info_for controller.request
212
+ end
213
+
214
+ should "send request data for manual notification with non-standard port" do
215
+ params = { 'controller' => "hoptoad_test", 'action' => "index" }
216
+ controller = process_action_with_manual_notification(:params => params, :port => 81)
217
+ assert_sent_request_info_for controller.request
218
+ end
219
+
220
+ should "send request data for automatic notification" do
221
+ params = { 'controller' => "hoptoad_test", 'action' => "index" }
222
+ controller = process_action_with_automatic_notification(:params => params)
223
+ assert_sent_request_info_for controller.request
224
+ end
225
+
226
+ should "send request data for automatic notification with non-standard port" do
227
+ params = { 'controller' => "hoptoad_test", 'action' => "index" }
228
+ controller = process_action_with_automatic_notification(:params => params, :port => 81)
229
+ assert_sent_request_info_for controller.request
230
+ end
231
+
232
+ should "use standard rails logging filters on params and env" do
233
+ filtered_params = { "abc" => "123",
234
+ "def" => "456",
235
+ "ghi" => "[FILTERED]" }
236
+ ENV['ghi'] = 'abc'
237
+ filtered_env = { 'ghi' => '[FILTERED]' }
238
+ filtered_cgi = { 'REQUEST_METHOD' => '[FILTERED]' }
239
+
240
+ process_action_with_automatic_notification(:filters => [:ghi, :request_method],
241
+ :params => { "abc" => "123",
242
+ "def" => "456",
243
+ "ghi" => "789" })
244
+ assert_sent_hash filtered_params, '/notice/request/params'
245
+ assert_sent_hash filtered_cgi, '/notice/request/cgi-data'
246
+ end
247
+
248
+ context "for a local error with development lookup enabled" do
249
+ setup do
250
+ HoptoadNotifier.configuration.development_lookup = true
251
+ HoptoadNotifier.stubs(:build_lookup_hash_for).returns({ :awesome => 2 })
252
+
253
+ @controller = process_action_with_automatic_notification(:local => true)
254
+ @response = @controller.response
255
+ end
256
+
257
+ should "append custom CSS and JS to response body for a local error" do
258
+ assert_match /text\/css/, @response.body
259
+ assert_match /text\/javascript/, @response.body
260
+ end
261
+
262
+ should "contain host, API key and notice JSON" do
263
+ assert_match HoptoadNotifier.configuration.host.to_json, @response.body
264
+ assert_match HoptoadNotifier.configuration.api_key.to_json, @response.body
265
+ assert_match ({ :awesome => 2 }).to_json, @response.body
266
+ end
267
+ end
268
+
269
+ context "for a local error with development lookup disabled" do
270
+ setup do
271
+ HoptoadNotifier.configuration.development_lookup = false
272
+
273
+ @controller = process_action_with_automatic_notification(:local => true)
274
+ @response = @controller.response
275
+ end
276
+
277
+ should "not append custom CSS and JS to response for a local error" do
278
+ assert_no_match /text\/css/, @response.body
279
+ assert_no_match /text\/javascript/, @response.body
280
+ end
281
+ end
282
+
283
+ should "call session.to_hash if available" do
284
+ hash_data = {:key => :value}
285
+
286
+ session = ActionController::TestSession.new
287
+ ActionController::TestSession.stubs(:new).returns(session)
288
+ session.stubs(:to_hash).returns(hash_data)
289
+
290
+ process_action_with_automatic_notification
291
+ assert_received(session, :to_hash)
292
+ assert_received(session, :data) { |expect| expect.never }
293
+ assert_caught_and_sent
294
+ end
295
+
296
+ should "call session.data if session.to_hash is undefined" do
297
+ hash_data = {:key => :value}
298
+
299
+ session = ActionController::TestSession.new
300
+ ActionController::TestSession.stubs(:new).returns(session)
301
+ session.stubs(:data).returns(hash_data)
302
+ if session.respond_to?(:to_hash)
303
+ class << session
304
+ undef to_hash
305
+ end
306
+ end
307
+
308
+ process_action_with_automatic_notification
309
+ assert_received(session, :to_hash) { |expect| expect.never }
310
+ assert_received(session, :data) { |expect| expect.at_least_once }
311
+ assert_caught_and_sent
312
+ end
313
+
314
+ end
@@ -0,0 +1,207 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ConfigurationTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ should "provide default values" do
8
+ assert_config_default :proxy_host, nil
9
+ assert_config_default :proxy_port, nil
10
+ assert_config_default :proxy_user, nil
11
+ assert_config_default :proxy_pass, nil
12
+ assert_config_default :project_root, nil
13
+ assert_config_default :environment_name, nil
14
+ assert_config_default :logger, nil
15
+ assert_config_default :notifier_version, HoptoadNotifier::VERSION
16
+ assert_config_default :notifier_name, 'Hoptoad Notifier'
17
+ assert_config_default :notifier_url, 'http://hoptoadapp.com'
18
+ assert_config_default :secure, false
19
+ assert_config_default :host, 'hoptoadapp.com'
20
+ assert_config_default :http_open_timeout, 2
21
+ assert_config_default :http_read_timeout, 5
22
+ assert_config_default :ignore_by_filters, []
23
+ assert_config_default :ignore_user_agent, []
24
+ assert_config_default :params_filters,
25
+ HoptoadNotifier::Configuration::DEFAULT_PARAMS_FILTERS
26
+ assert_config_default :backtrace_filters,
27
+ HoptoadNotifier::Configuration::DEFAULT_BACKTRACE_FILTERS
28
+ assert_config_default :ignore,
29
+ HoptoadNotifier::Configuration::IGNORE_DEFAULT
30
+ assert_config_default :development_lookup, true
31
+ end
32
+
33
+ should "provide default values for secure connections" do
34
+ config = HoptoadNotifier::Configuration.new
35
+ config.secure = true
36
+ assert_equal 443, config.port
37
+ assert_equal 'https', config.protocol
38
+ end
39
+
40
+ should "provide default values for insecure connections" do
41
+ config = HoptoadNotifier::Configuration.new
42
+ config.secure = false
43
+ assert_equal 80, config.port
44
+ assert_equal 'http', config.protocol
45
+ end
46
+
47
+ should "not cache inferred ports" do
48
+ config = HoptoadNotifier::Configuration.new
49
+ config.secure = false
50
+ config.port
51
+ config.secure = true
52
+ assert_equal 443, config.port
53
+ end
54
+
55
+ should "allow values to be overwritten" do
56
+ assert_config_overridable :proxy_host
57
+ assert_config_overridable :proxy_port
58
+ assert_config_overridable :proxy_user
59
+ assert_config_overridable :proxy_pass
60
+ assert_config_overridable :secure
61
+ assert_config_overridable :host
62
+ assert_config_overridable :port
63
+ assert_config_overridable :http_open_timeout
64
+ assert_config_overridable :http_read_timeout
65
+ assert_config_overridable :project_root
66
+ assert_config_overridable :notifier_version
67
+ assert_config_overridable :notifier_name
68
+ assert_config_overridable :notifier_url
69
+ assert_config_overridable :environment_name
70
+ assert_config_overridable :development_lookup
71
+ assert_config_overridable :logger
72
+ end
73
+
74
+ should "have an api key" do
75
+ assert_config_overridable :api_key
76
+ end
77
+
78
+ should "act like a hash" do
79
+ config = HoptoadNotifier::Configuration.new
80
+ hash = config.to_hash
81
+ [:api_key, :backtrace_filters, :development_environments,
82
+ :environment_name, :host, :http_open_timeout,
83
+ :http_read_timeout, :ignore, :ignore_by_filters, :ignore_user_agent,
84
+ :notifier_name, :notifier_url, :notifier_version, :params_filters,
85
+ :project_root, :port, :protocol, :proxy_host, :proxy_pass, :proxy_port,
86
+ :proxy_user, :secure, :development_lookup].each do |option|
87
+ assert_equal config[option], hash[option], "Wrong value for #{option}"
88
+ end
89
+ end
90
+
91
+ should "be mergable" do
92
+ config = HoptoadNotifier::Configuration.new
93
+ hash = config.to_hash
94
+ assert_equal hash.merge(:key => 'value'), config.merge(:key => 'value')
95
+ end
96
+
97
+ should "allow param filters to be appended" do
98
+ assert_appends_value :params_filters
99
+ end
100
+
101
+ should "warn when attempting to read environment filters" do
102
+ config = HoptoadNotifier::Configuration.new
103
+ config.
104
+ expects(:warn).
105
+ with(regexp_matches(/deprecated/i))
106
+ assert_equal [], config.environment_filters
107
+ end
108
+
109
+ should "allow ignored user agents to be appended" do
110
+ assert_appends_value :ignore_user_agent
111
+ end
112
+
113
+ should "allow backtrace filters to be appended" do
114
+ assert_appends_value(:backtrace_filters) do |config|
115
+ new_filter = lambda {}
116
+ config.filter_backtrace(&new_filter)
117
+ new_filter
118
+ end
119
+ end
120
+
121
+ should "allow ignore by filters to be appended" do
122
+ assert_appends_value(:ignore_by_filters) do |config|
123
+ new_filter = lambda {}
124
+ config.ignore_by_filter(&new_filter)
125
+ new_filter
126
+ end
127
+ end
128
+
129
+ should "allow ignored exceptions to be appended" do
130
+ config = HoptoadNotifier::Configuration.new
131
+ original_filters = config.ignore.dup
132
+ new_filter = 'hello'
133
+ config.ignore << new_filter
134
+ assert_same_elements original_filters + [new_filter], config.ignore
135
+ end
136
+
137
+ should "allow ignored exceptions to be replaced" do
138
+ assert_replaces(:ignore, :ignore_only=)
139
+ end
140
+
141
+ should "allow ignored user agents to be replaced" do
142
+ assert_replaces(:ignore_user_agent, :ignore_user_agent_only=)
143
+ end
144
+
145
+ should "use development and test as development environments by default" do
146
+ config = HoptoadNotifier::Configuration.new
147
+ assert_same_elements %w(development test cucumber), config.development_environments
148
+ end
149
+
150
+ should "be public in a public environment" do
151
+ config = HoptoadNotifier::Configuration.new
152
+ config.development_environments = %w(development)
153
+ config.environment_name = 'production'
154
+ assert config.public?
155
+ end
156
+
157
+ should "not be public in a development environment" do
158
+ config = HoptoadNotifier::Configuration.new
159
+ config.development_environments = %w(staging)
160
+ config.environment_name = 'staging'
161
+ assert !config.public?
162
+ end
163
+
164
+ should "be public without an environment name" do
165
+ config = HoptoadNotifier::Configuration.new
166
+ assert config.public?
167
+ end
168
+
169
+ should "use the assigned logger if set" do
170
+ config = HoptoadNotifier::Configuration.new
171
+ config.logger = "CUSTOM LOGGER"
172
+ assert_equal "CUSTOM LOGGER", config.logger
173
+ end
174
+
175
+ def assert_config_default(option, default_value, config = nil)
176
+ config ||= HoptoadNotifier::Configuration.new
177
+ assert_equal default_value, config.send(option)
178
+ end
179
+
180
+ def assert_config_overridable(option, value = 'a value')
181
+ config = HoptoadNotifier::Configuration.new
182
+ config.send(:"#{option}=", value)
183
+ assert_equal value, config.send(option)
184
+ end
185
+
186
+ def assert_appends_value(option, &block)
187
+ config = HoptoadNotifier::Configuration.new
188
+ original_values = config.send(option).dup
189
+ block ||= lambda do |config|
190
+ new_value = 'hello'
191
+ config.send(option) << new_value
192
+ new_value
193
+ end
194
+ new_value = block.call(config)
195
+ assert_same_elements original_values + [new_value], config.send(option)
196
+ end
197
+
198
+ def assert_replaces(option, setter)
199
+ config = HoptoadNotifier::Configuration.new
200
+ new_value = 'hello'
201
+ config.send(setter, [new_value])
202
+ assert_equal [new_value], config.send(option)
203
+ config.send(setter, new_value)
204
+ assert_equal [new_value], config.send(option)
205
+ end
206
+
207
+ end