hydraulic_brake 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class LoggerTest < Test::Unit::TestCase
4
+ def stub_http(response, body = nil)
5
+ response.stubs(:body => body) if body
6
+ @http = stub(:post => response,
7
+ :read_timeout= => nil,
8
+ :open_timeout= => nil,
9
+ :use_ssl= => nil)
10
+ Net::HTTP.stubs(:new).returns(@http)
11
+ end
12
+
13
+ def send_notice
14
+ HydraulicBrake.sender.send_to_airbrake({'foo' => "bar"})
15
+ end
16
+
17
+ def stub_verbose_log
18
+ HydraulicBrake.stubs(:write_verbose_log)
19
+ end
20
+
21
+ def configure
22
+ HydraulicBrake.configure { |config| }
23
+ end
24
+
25
+ should "report that notifier is ready when configured" do
26
+ stub_verbose_log
27
+ configure
28
+ assert_logged /Notifier (.*) ready/
29
+ end
30
+
31
+ should "not report that notifier is ready when internally configured" do
32
+ stub_verbose_log
33
+ HydraulicBrake.configure(true) { |config| }
34
+ assert_not_logged /.*/
35
+ end
36
+
37
+ should "print environment info a successful notification without a body" do
38
+ reset_config
39
+ stub_verbose_log
40
+ stub_http(Net::HTTPSuccess)
41
+ send_notice
42
+ assert_logged /Environment Info:/
43
+ assert_not_logged /Response from Airbrake:/
44
+ end
45
+
46
+ should "print environment info on a failed notification without a body" do
47
+ reset_config
48
+ stub_verbose_log
49
+ stub_http(Net::HTTPError)
50
+ send_notice
51
+ assert_logged /Environment Info:/
52
+ assert_not_logged /Response from Airbrake:/
53
+ end
54
+
55
+ should "print environment info and response on a success with a body" do
56
+ reset_config
57
+ stub_verbose_log
58
+ stub_http(Net::HTTPSuccess, 'test')
59
+ send_notice
60
+ assert_logged /Environment Info:/
61
+ assert_logged /Response from Airbrake:/
62
+ end
63
+
64
+ should "print environment info and response on a failure with a body" do
65
+ reset_config
66
+ stub_verbose_log
67
+ stub_http(Net::HTTPError, 'test')
68
+ send_notice
69
+ assert_logged /Environment Info:/
70
+ assert_logged /Response from Airbrake:/
71
+ end
72
+
73
+ should "print information about the notice when Airbrake server fails" do
74
+ stub_verbose_log
75
+ stub_http(Net::HTTPError, "test")
76
+ send_notice
77
+ assert_logged /Notice details:/
78
+ end
79
+ end
@@ -0,0 +1,324 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class NoticeTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ def configure
8
+ HydraulicBrake::Configuration.new.tap do |config|
9
+ config.api_key = 'abc123def456'
10
+ end
11
+ end
12
+
13
+ def build_notice(args = {})
14
+ configuration = args.delete(:configuration) || configure
15
+ HydraulicBrake::Notice.new(configuration.merge(args))
16
+ end
17
+
18
+ def stub_request(attrs = {})
19
+ stub('request', { :parameters => { 'one' => 'two' },
20
+ :protocol => 'http',
21
+ :host => 'some.host',
22
+ :request_uri => '/some/uri',
23
+ :session => { :to_hash => { 'a' => 'b' } },
24
+ :env => { 'three' => 'four' } }.update(attrs))
25
+ end
26
+
27
+ def assert_accepts_exception_attribute(attribute, args = {}, &block)
28
+ exception = build_exception
29
+ block ||= lambda { exception.send(attribute) }
30
+ value = block.call(exception)
31
+
32
+ notice_from_exception = build_notice(args.merge(:exception => exception))
33
+
34
+ assert_equal notice_from_exception.send(attribute),
35
+ value,
36
+ "#{attribute} was not correctly set from an exception"
37
+
38
+ notice_from_hash = build_notice(args.merge(attribute => value))
39
+ assert_equal notice_from_hash.send(attribute),
40
+ value,
41
+ "#{attribute} was not correctly set from a hash"
42
+ end
43
+
44
+ def assert_valid_notice_document(document)
45
+ xsd_path = File.join(File.dirname(__FILE__), "airbrake_2_3.xsd")
46
+ schema = Nokogiri::XML::Schema.new(IO.read(xsd_path))
47
+ errors = schema.validate(document)
48
+ assert errors.empty?, errors.collect{|e| e.message }.join
49
+ end
50
+
51
+ def build_backtrace_array
52
+ ["app/models/user.rb:13:in `magic'",
53
+ "app/controllers/users_controller.rb:8:in `index'"]
54
+ end
55
+
56
+ def hostname
57
+ `hostname`.chomp
58
+ end
59
+
60
+ def user
61
+ Struct.new(:email,:id,:name).
62
+ new("darth@vader.com",1,"Anakin Skywalker")
63
+ end
64
+
65
+ should "set the api key" do
66
+ api_key = 'key'
67
+ notice = build_notice(:api_key => api_key)
68
+ assert_equal api_key, notice.api_key
69
+ end
70
+
71
+ should "accept a project root" do
72
+ project_root = '/path/to/project'
73
+ notice = build_notice(:project_root => project_root)
74
+ assert_equal project_root, notice.project_root
75
+ end
76
+
77
+ should "accept a component" do
78
+ assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
79
+ end
80
+
81
+ should "alias the component as controller" do
82
+ assert_equal 'users_controller', build_notice(:controller => 'users_controller').component
83
+ assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
84
+ end
85
+
86
+ should "accept a action" do
87
+ assert_equal 'index', build_notice(:action => 'index').action
88
+ end
89
+
90
+ should "accept a url" do
91
+ url = 'http://some.host/uri'
92
+ notice = build_notice(:url => url)
93
+ assert_equal url, notice.url
94
+ end
95
+
96
+ should "set the host name" do
97
+ notice = build_notice
98
+ assert_equal hostname, notice.hostname
99
+ end
100
+
101
+ should "accept a backtrace from an exception or hash" do
102
+ array = ["user.rb:34:in `crazy'"]
103
+ exception = build_exception
104
+ exception.set_backtrace array
105
+ backtrace = HydraulicBrake::Backtrace.parse(array)
106
+ notice_from_exception = build_notice(:exception => exception)
107
+
108
+
109
+ assert_equal backtrace,
110
+ notice_from_exception.backtrace,
111
+ "backtrace was not correctly set from an exception"
112
+
113
+ notice_from_hash = build_notice(:backtrace => array)
114
+ assert_equal backtrace,
115
+ notice_from_hash.backtrace,
116
+ "backtrace was not correctly set from a hash"
117
+ end
118
+
119
+ should "accept user" do
120
+ assert_equal user.id, build_notice(:user => user).user.id
121
+ assert_equal user.email, build_notice(:user => user).user.email
122
+ assert_equal user.name, build_notice(:user => user).user.name
123
+ end
124
+
125
+ should "pass its backtrace filters for parsing" do
126
+ backtrace_array = ['my/file/backtrace:3']
127
+ exception = build_exception
128
+ exception.set_backtrace(backtrace_array)
129
+ HydraulicBrake::Backtrace.expects(:parse).with(backtrace_array, {:filters => 'foo'})
130
+
131
+ notice = HydraulicBrake::Notice.new({:exception => exception, :backtrace_filters => 'foo'})
132
+ end
133
+
134
+ should "set the error class from an exception or hash" do
135
+ assert_accepts_exception_attribute :error_class do |exception|
136
+ exception.class.name
137
+ end
138
+ end
139
+
140
+ should "set the error message from an exception or hash" do
141
+ assert_accepts_exception_attribute :error_message do |exception|
142
+ "#{exception.class.name}: #{exception.message}"
143
+ end
144
+ end
145
+
146
+ should "accept parameters from a request or hash" do
147
+ parameters = { 'one' => 'two' }
148
+ notice_from_hash = build_notice(:parameters => parameters)
149
+ assert_equal notice_from_hash.parameters, parameters
150
+ end
151
+
152
+ should "accept session data from a session_data hash" do
153
+ data = { 'one' => 'two' }
154
+ notice = build_notice(:session_data => data)
155
+ assert_equal data, notice.session_data
156
+ end
157
+
158
+ should "accept an environment name" do
159
+ assert_equal 'development', build_notice(:environment_name => 'development').environment_name
160
+ end
161
+
162
+ should "accept CGI data from a hash" do
163
+ data = { 'string' => 'value' }
164
+ notice = build_notice(:cgi_data => data)
165
+ assert_equal data, notice.cgi_data, "should take CGI data from a hash"
166
+ end
167
+
168
+ should "accept notifier information" do
169
+ params = { :notifier_name => 'a name for a notifier',
170
+ :notifier_version => '1.0.5',
171
+ :notifier_url => 'http://notifiers.r.us/download' }
172
+ notice = build_notice(params)
173
+ assert_equal params[:notifier_name], notice.notifier_name
174
+ assert_equal params[:notifier_version], notice.notifier_version
175
+ assert_equal params[:notifier_url], notice.notifier_url
176
+ end
177
+
178
+ should "set sensible defaults without an exception" do
179
+ backtrace = HydraulicBrake::Backtrace.parse(build_backtrace_array)
180
+ notice = build_notice(:backtrace => build_backtrace_array)
181
+
182
+ assert_equal 'Notification', notice.error_message
183
+ assert_array_starts_with backtrace.lines, notice.backtrace.lines
184
+ assert_equal({}, notice.parameters)
185
+ assert_equal({}, notice.session_data)
186
+ end
187
+
188
+ should "use the caller as the backtrace for an exception without a backtrace" do
189
+ filters = HydraulicBrake::Configuration.new.backtrace_filters
190
+ backtrace = HydraulicBrake::Backtrace.parse(caller, :filters => filters)
191
+ notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
192
+
193
+ assert_array_starts_with backtrace.lines, notice.backtrace.lines
194
+ end
195
+
196
+ context "a Notice turned into XML" do
197
+ setup do
198
+ HydraulicBrake.configure do |config|
199
+ config.api_key = "1234567890"
200
+ end
201
+
202
+ @exception = build_exception
203
+
204
+ @notice = build_notice({
205
+ :notifier_name => 'a name',
206
+ :notifier_version => '1.2.3',
207
+ :notifier_url => 'http://some.url/path',
208
+ :exception => @exception,
209
+ :controller => "controller",
210
+ :action => "action",
211
+ :url => "http://url.com",
212
+ :parameters => { "paramskey" => "paramsvalue",
213
+ "nestparentkey" => { "nestkey" => "nestvalue" } },
214
+ :session_data => { "sessionkey" => "sessionvalue" },
215
+ :cgi_data => { "cgikey" => "cgivalue" },
216
+ :project_root => "RAILS_ROOT",
217
+ :environment_name => "RAILS_ENV"
218
+ })
219
+
220
+ @xml = @notice.to_xml
221
+
222
+ @document = Nokogiri::XML::Document.parse(@xml)
223
+ end
224
+
225
+ should "validate against the XML schema" do
226
+ assert_valid_notice_document @document
227
+ end
228
+
229
+ should "serialize a Notice to XML when sent #to_xml" do
230
+ assert_valid_node(@document, "//api-key", @notice.api_key)
231
+
232
+ assert_valid_node(@document, "//notifier/name", @notice.notifier_name)
233
+ assert_valid_node(@document, "//notifier/version", @notice.notifier_version)
234
+ assert_valid_node(@document, "//notifier/url", @notice.notifier_url)
235
+
236
+ assert_valid_node(@document, "//error/class", @notice.error_class)
237
+ assert_valid_node(@document, "//error/message", @notice.error_message)
238
+
239
+ assert_valid_node(@document, "//error/backtrace/line/@number", @notice.backtrace.lines.first.number)
240
+ assert_valid_node(@document, "//error/backtrace/line/@file", @notice.backtrace.lines.first.file)
241
+ assert_valid_node(@document, "//error/backtrace/line/@method", @notice.backtrace.lines.first.method)
242
+
243
+ assert_valid_node(@document, "//request/url", @notice.url)
244
+ assert_valid_node(@document, "//request/component", @notice.controller)
245
+ assert_valid_node(@document, "//request/action", @notice.action)
246
+
247
+ assert_valid_node(@document, "//request/params/var/@key", "paramskey")
248
+ assert_valid_node(@document, "//request/params/var", "paramsvalue")
249
+ assert_valid_node(@document, "//request/params/var/@key", "nestparentkey")
250
+ assert_valid_node(@document, "//request/params/var/var/@key", "nestkey")
251
+ assert_valid_node(@document, "//request/params/var/var", "nestvalue")
252
+ assert_valid_node(@document, "//request/session/var/@key", "sessionkey")
253
+ assert_valid_node(@document, "//request/session/var", "sessionvalue")
254
+ assert_valid_node(@document, "//request/cgi-data/var/@key", "cgikey")
255
+ assert_valid_node(@document, "//request/cgi-data/var", "cgivalue")
256
+
257
+ assert_valid_node(@document, "//server-environment/project-root", "RAILS_ROOT")
258
+ assert_valid_node(@document, "//server-environment/environment-name", "RAILS_ENV")
259
+ assert_valid_node(@document, "//server-environment/hostname", hostname)
260
+ end
261
+ end
262
+
263
+ should "not send empty request data" do
264
+ notice = build_notice
265
+ assert_nil notice.url
266
+ assert_nil notice.controller
267
+ assert_nil notice.action
268
+
269
+ xml = notice.to_xml
270
+ document = Nokogiri::XML.parse(xml)
271
+ assert_nil document.at('//request/url')
272
+ assert_nil document.at('//request/component')
273
+ assert_nil document.at('//request/action')
274
+
275
+ assert_valid_notice_document document
276
+ end
277
+
278
+ %w(url controller action).each do |var|
279
+ should "send a request if #{var} is present" do
280
+ notice = build_notice(var.to_sym => 'value')
281
+ xml = notice.to_xml
282
+ document = Nokogiri::XML.parse(xml)
283
+ assert_not_nil document.at('//request')
284
+ end
285
+ end
286
+
287
+ %w(parameters cgi_data session_data).each do |var|
288
+ should "send a request if #{var} is present" do
289
+ notice = build_notice(var.to_sym => { 'key' => 'value' })
290
+ xml = notice.to_xml
291
+ document = Nokogiri::XML.parse(xml)
292
+ assert_not_nil document.at('//request')
293
+ end
294
+ end
295
+
296
+ should "act like a hash" do
297
+ notice = build_notice(:error_message => 'some message')
298
+ assert_equal notice.error_message, notice[:error_message]
299
+ end
300
+
301
+ should "return params on notice[:request][:params]" do
302
+ params = { 'one' => 'two' }
303
+ notice = build_notice(:parameters => params)
304
+ assert_equal params, notice[:request][:params]
305
+ end
306
+
307
+ should "ensure #to_hash is called on objects that support it" do
308
+ assert_nothing_raised do
309
+ build_notice(:session => { :object => stub(:to_hash => {}) })
310
+ end
311
+ end
312
+
313
+ should "ensure #to_ary is called on objects that support it" do
314
+ assert_nothing_raised do
315
+ build_notice(:session => { :object => stub(:to_ary => {}) })
316
+ end
317
+ end
318
+
319
+ should "prefer passed error_message to exception message" do
320
+ exception = build_exception
321
+ notice = build_notice(:exception => exception,:error_message => "Random ponies")
322
+ assert_equal "BacktracedException: Random ponies", notice.error_message
323
+ end
324
+ end
@@ -0,0 +1,220 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class NotifierTest < Test::Unit::TestCase
4
+
5
+ class OriginalException < Exception
6
+ end
7
+
8
+ class ContinuedException < Exception
9
+ end
10
+
11
+ include DefinesConstants
12
+
13
+ def setup
14
+ super
15
+ reset_config
16
+ end
17
+
18
+ def assert_sent(notice, notice_args)
19
+ assert_received(HydraulicBrake::Notice, :new) {|expect| expect.with(has_entries(notice_args)) }
20
+ assert_received(HydraulicBrake.sender, :send_to_airbrake) {|expect| expect.with(notice) }
21
+ end
22
+
23
+ def set_public_env
24
+ HydraulicBrake.configure { |config| config.environment_name = 'production' }
25
+ end
26
+
27
+ def set_development_env
28
+ HydraulicBrake.configure { |config| config.environment_name = 'development' }
29
+ end
30
+
31
+ should "yield and save a configuration when configuring" do
32
+ yielded_configuration = nil
33
+ HydraulicBrake.configure do |config|
34
+ yielded_configuration = config
35
+ end
36
+
37
+ assert_kind_of HydraulicBrake::Configuration, yielded_configuration
38
+ assert_equal yielded_configuration, HydraulicBrake.configuration
39
+ end
40
+
41
+ should "not remove existing config options when configuring twice" do
42
+ first_config = nil
43
+ HydraulicBrake.configure do |config|
44
+ first_config = config
45
+ end
46
+ HydraulicBrake.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
+ HydraulicBrake::Sender.stubs(:new => sender)
54
+ configuration = nil
55
+
56
+ HydraulicBrake.configure { |yielded_config| configuration = yielded_config }
57
+
58
+ assert_received(HydraulicBrake::Sender, :new) { |expect| expect.with(configuration) }
59
+ assert_equal sender, HydraulicBrake.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
+ HydraulicBrake.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
+ HydraulicBrake.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
+ HydraulicBrake.notify(notice_args)
91
+
92
+ assert_received(HydraulicBrake::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
+ HydraulicBrake.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
+ HydraulicBrake.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
+ HydraulicBrake.notify(build_exception)
125
+
126
+ assert_received(sender, :send_to_airbrake) {|expect| expect.never }
127
+ end
128
+
129
+ should "pass config to created notices" do
130
+ exception = build_exception
131
+ config_opts = { 'one' => 'two', 'three' => 'four' }
132
+ stub_notice!
133
+ stub_sender!
134
+ HydraulicBrake.configuration = stub('config', :merge => config_opts, :public? => true)
135
+
136
+ HydraulicBrake.notify(exception)
137
+
138
+ assert_received(HydraulicBrake::Notice, :new) do |expect|
139
+ expect.with(has_entries(config_opts))
140
+ end
141
+ end
142
+
143
+ context "building notice JSON for an exception" do
144
+ setup do
145
+ @params = { :controller => "users", :action => "create" }
146
+ @exception = build_exception
147
+ @hash = HydraulicBrake.build_lookup_hash_for(@exception, @params)
148
+ end
149
+
150
+ should "set action" do
151
+ assert_equal @params[:action], @hash[:action]
152
+ end
153
+
154
+ should "set controller" do
155
+ assert_equal @params[:controller], @hash[:component]
156
+ end
157
+
158
+ should "set line number" do
159
+ assert @hash[:line_number] =~ /\d+/
160
+ end
161
+
162
+ should "set file" do
163
+ assert_match(/test\/helper\.rb$/, @hash[:file])
164
+ end
165
+
166
+ should "set env to production" do
167
+ assert_equal 'production', @hash[:environment_name]
168
+ end
169
+
170
+ should "set error class" do
171
+ assert_equal @exception.class.to_s, @hash[:error_class]
172
+ end
173
+
174
+ should "not set file or line number with no backtrace" do
175
+ @exception.stubs(:backtrace).returns([])
176
+
177
+ @hash = HydraulicBrake.build_lookup_hash_for(@exception)
178
+
179
+ assert_nil @hash[:line_number]
180
+ assert_nil @hash[:file]
181
+ end
182
+
183
+ should "not set action or controller when not provided" do
184
+ @hash = HydraulicBrake.build_lookup_hash_for(@exception)
185
+
186
+ assert_nil @hash[:action]
187
+ assert_nil @hash[:controller]
188
+ end
189
+
190
+ context "when an exception that provides #original_exception is raised" do
191
+ setup do
192
+ @exception.stubs(:original_exception).returns(begin
193
+ raise NotifierTest::OriginalException.new
194
+ rescue Exception => e
195
+ e
196
+ end)
197
+ end
198
+
199
+ should "unwrap exceptions that provide #original_exception" do
200
+ @hash = HydraulicBrake.build_lookup_hash_for(@exception)
201
+ assert_equal "NotifierTest::OriginalException", @hash[:error_class]
202
+ end
203
+ end
204
+
205
+ context "when an exception that provides #continued_exception is raised" do
206
+ setup do
207
+ @exception.stubs(:continued_exception).returns(begin
208
+ raise NotifierTest::ContinuedException.new
209
+ rescue Exception => e
210
+ e
211
+ end)
212
+ end
213
+
214
+ should "unwrap exceptions that provide #continued_exception" do
215
+ @hash = HydraulicBrake.build_lookup_hash_for(@exception)
216
+ assert_equal "NotifierTest::ContinuedException", @hash[:error_class]
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,10 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ class RecursionTest < Test::Unit::TestCase
4
+ should "not allow infinite recursion" do
5
+ hash = {:a => :a}
6
+ hash[:hash] = hash
7
+ notice = HydraulicBrake::Notice.new(:parameters => hash)
8
+ assert_equal "[possible infinite recursion halted]", notice.parameters[:hash]
9
+ end
10
+ end