honeybadger 1.9.5 → 1.10.0.beta1
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.
- data/Appraisals +0 -12
- data/CHANGELOG.md +19 -5
- data/Gemfile.lock +1 -5
- data/MIT-LICENSE +6 -5
- data/README.md +6 -596
- data/Rakefile +5 -5
- data/features/rails.feature +37 -12
- data/features/step_definitions/rails_steps.rb +20 -0
- data/features/support/honeybadger_shim.rb.template +3 -5
- data/gemfiles/rack.gemfile +0 -1
- data/gemfiles/rack.gemfile.lock +1 -8
- data/gemfiles/rails2.3.gemfile +0 -1
- data/gemfiles/rails2.3.gemfile.lock +1 -8
- data/gemfiles/rails3.0.gemfile +0 -2
- data/gemfiles/rails3.0.gemfile.lock +2 -12
- data/gemfiles/rails3.1.gemfile +0 -2
- data/gemfiles/rails3.1.gemfile.lock +3 -13
- data/gemfiles/rails3.2.gemfile +0 -2
- data/gemfiles/rails3.2.gemfile.lock +4 -14
- data/gemfiles/rails4.gemfile +0 -2
- data/gemfiles/rails4.gemfile.lock +4 -14
- data/gemfiles/rake.gemfile +0 -1
- data/gemfiles/rake.gemfile.lock +1 -8
- data/gemfiles/sinatra.gemfile +0 -1
- data/gemfiles/sinatra.gemfile.lock +1 -8
- data/honeybadger.gemspec +7 -3
- data/lib/honeybadger.rb +7 -5
- data/lib/honeybadger/configuration.rb +7 -3
- data/lib/honeybadger/monitor/sender.rb +4 -6
- data/lib/honeybadger/notice.rb +30 -4
- data/lib/honeybadger/rails.rb +2 -0
- data/lib/honeybadger/rails3_tasks.rb +2 -2
- data/lib/honeybadger/railtie.rb +3 -1
- data/lib/honeybadger/sender.rb +63 -53
- data/lib/honeybadger/templates/feedback_form.html.erb +82 -0
- data/lib/honeybadger/user_feedback.rb +42 -0
- data/lib/honeybadger/user_informer.rb +26 -0
- data/spec/honeybadger/configuration_spec.rb +4 -1
- data/spec/honeybadger/logger_spec.rb +25 -2
- data/spec/honeybadger/notice_spec.rb +69 -3
- data/spec/honeybadger/sender_spec.rb +77 -54
- data/spec/honeybadger/user_feedback_spec.rb +55 -0
- data/spec/honeybadger/user_informer_spec.rb +30 -0
- data/spec/support/helpers.rb +9 -6
- metadata +63 -39
- checksums.yaml +0 -7
@@ -0,0 +1,82 @@
|
|
1
|
+
<style>
|
2
|
+
#honeybadger_feedback_form *, #honeybadger_feedback_form *:before, #honeybadger_feedback_form *:after { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
|
3
|
+
#honeybadger_feedback_form h2 { font-size: 110%; line-height: 1.5em; }
|
4
|
+
#honeybadger_feedback_form label { font-weight: bold; }
|
5
|
+
#honeybadger_feedback_name, #honeybadger_feedback_email, #honeybadger_feedback_comment { width: 100%; padding: 0.5em; }
|
6
|
+
#honeybadger_feedback_comment { height: 10em; }
|
7
|
+
#honeybadger_feedback_submit { height: 1em; }
|
8
|
+
#honeybadger_feedback_form .honeybadger-feedback-phone { display: none; }
|
9
|
+
</style>
|
10
|
+
|
11
|
+
<script>
|
12
|
+
function honeybadgerFeedbackResponse(data) {
|
13
|
+
if (data['result'] == 'OK') {
|
14
|
+
var form = document.getElementById('honeybadger_feedback_form');
|
15
|
+
var success = document.getElementById('honeybadger_feedback_success');
|
16
|
+
|
17
|
+
form.style.display = 'none';
|
18
|
+
success.style.display = 'block';
|
19
|
+
} else {
|
20
|
+
var message;
|
21
|
+
|
22
|
+
if (data['error']) {
|
23
|
+
message = data['error'];
|
24
|
+
} else {
|
25
|
+
message = "An unknown error occurred. Please try again.";
|
26
|
+
}
|
27
|
+
|
28
|
+
alert(message);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
function sendHoneybadgerFeedback() {
|
33
|
+
try {
|
34
|
+
var script = document.createElement('script');
|
35
|
+
var form = document.getElementById('honeybadger_feedback_form');
|
36
|
+
script.src = '<%= action %>?format=js&token=<%= error_id %>&name=' + encodeURIComponent(form.name.value) + '&email=' + encodeURIComponent(form.email.value) + '&comment=' + encodeURIComponent(form.comment.value);
|
37
|
+
form.appendChild(script);
|
38
|
+
return false;
|
39
|
+
} catch(e) {
|
40
|
+
if (window.console) {
|
41
|
+
console.log('Error caught while processing Honeybadger feedback form: ' + e);
|
42
|
+
console.log('Submitting form normally...');
|
43
|
+
}
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
}
|
47
|
+
</script>
|
48
|
+
|
49
|
+
<div id="honeybadger_feedback_success" style="display:none;">
|
50
|
+
<p><strong>Thanks for the feedback!</strong></p>
|
51
|
+
</div>
|
52
|
+
|
53
|
+
<form action="<%= action %>" method="POST" id="honeybadger_feedback_form" onsubmit="return sendHoneybadgerFeedback();">
|
54
|
+
<input type="hidden" name="token" id="honeybadger_feedback_token" value="<%= error_id %>">
|
55
|
+
|
56
|
+
<h2>Care to help us fix this?</h2>
|
57
|
+
<p>Any information you can provide will help our technical team get to the bottom of this issue.</p>
|
58
|
+
|
59
|
+
<p class="honeybadger-feedback-name">
|
60
|
+
<label for="honeybadger_feedback_name">Your name</label><br>
|
61
|
+
<input type="text" name="name" id="honeybadger_feedback_name" size="60">
|
62
|
+
</p>
|
63
|
+
|
64
|
+
<p class="honeybadger-feedback-phone">
|
65
|
+
<label for="honeybadger_feedback_phone">Your phone number</label><br>
|
66
|
+
<input type="text" name="phone" id="honeybadger_feedback_phone" size="60">
|
67
|
+
</p>
|
68
|
+
|
69
|
+
<p class="honeybadger-feedback-email">
|
70
|
+
<label for="honeybadger_feedback_email">Your email address</label><br>
|
71
|
+
<input type="email" name="email" id="honeybadger_feedback_email" size="60">
|
72
|
+
</p>
|
73
|
+
|
74
|
+
<p class="honeybadger-feedback-comment">
|
75
|
+
<label for="honeybadger_feedback_comment">Comment (required)</label><br>
|
76
|
+
<textarea name="comment" id="honeybadger_feedback_comment" cols="50" rows="6" required></textarea>
|
77
|
+
</p>
|
78
|
+
|
79
|
+
<p class="honeybadger-feedback-submit">
|
80
|
+
<input type="submit" id="honeybadger_feedback_submit" value="Send">
|
81
|
+
</p>
|
82
|
+
</form>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Honeybadger
|
5
|
+
class UserFeedback
|
6
|
+
TEMPLATE = File.read(File.expand_path('../templates/feedback_form.html.erb', __FILE__)).freeze
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def action
|
13
|
+
config = Honeybadger.configuration
|
14
|
+
URI.parse("#{config.protocol}://#{config.host}:#{config.port}/v1/feedback/").to_s
|
15
|
+
rescue URI::InvalidURIError
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_form(error_id, action = action)
|
20
|
+
return unless action
|
21
|
+
ERB.new(TEMPLATE).result(binding)
|
22
|
+
end
|
23
|
+
|
24
|
+
def enabled?
|
25
|
+
Honeybadger.configuration.feedback && Honeybadger.configuration.features['feedback']
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
status, headers, body = @app.call(env)
|
30
|
+
if enabled? && env['honeybadger.error_id'] && form = render_form(env['honeybadger.error_id'])
|
31
|
+
new_body = []
|
32
|
+
body.each do |chunk|
|
33
|
+
new_body << chunk.gsub("<!-- HONEYBADGER FEEDBACK -->", form)
|
34
|
+
end
|
35
|
+
body.close if body.respond_to?(:close)
|
36
|
+
headers['Content-Length'] = new_body.reduce(0) { |a,e| a += e.bytesize }.to_s
|
37
|
+
body = new_body
|
38
|
+
end
|
39
|
+
[status, headers, body]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Honeybadger
|
2
|
+
class UserInformer
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
5
|
+
end
|
6
|
+
|
7
|
+
def replacement(with)
|
8
|
+
Honeybadger.configuration.user_information.gsub(/\{\{\s*error_id\s*\}\}/, with.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
status, headers, body = @app.call(env)
|
13
|
+
if env['honeybadger.error_id'] && Honeybadger.configuration.user_information
|
14
|
+
new_body = []
|
15
|
+
replace = replacement(env['honeybadger.error_id'])
|
16
|
+
body.each do |chunk|
|
17
|
+
new_body << chunk.gsub("<!-- HONEYBADGER ERROR -->", replace)
|
18
|
+
end
|
19
|
+
body.close if body.respond_to?(:close)
|
20
|
+
headers['Content-Length'] = new_body.reduce(0) { |a,e| a += e.bytesize }.to_s
|
21
|
+
body = new_body
|
22
|
+
end
|
23
|
+
[status, headers, body]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -32,6 +32,7 @@ describe Honeybadger::Configuration do
|
|
32
32
|
assert_config_default :debug, false
|
33
33
|
assert_config_default :fingerprint, nil
|
34
34
|
assert_config_default :hostname, Socket.gethostname
|
35
|
+
assert_config_default :feedback, true
|
35
36
|
end
|
36
37
|
|
37
38
|
it "configures async as Proc" do
|
@@ -113,6 +114,8 @@ describe Honeybadger::Configuration do
|
|
113
114
|
assert_config_overridable :send_request_session
|
114
115
|
assert_config_overridable :debug
|
115
116
|
assert_config_overridable :hostname
|
117
|
+
assert_config_overridable :metrics
|
118
|
+
assert_config_overridable :feedback
|
116
119
|
end
|
117
120
|
|
118
121
|
it "has an api key" do
|
@@ -128,7 +131,7 @@ describe Honeybadger::Configuration do
|
|
128
131
|
:notifier_version, :params_filters, :project_root, :port, :protocol,
|
129
132
|
:proxy_host, :proxy_pass, :proxy_port, :proxy_user, :secure,
|
130
133
|
:source_extract_radius, :async, :send_request_session, :debug,
|
131
|
-
:fingerprint, :hostname].each do |option|
|
134
|
+
:fingerprint, :hostname, :metrics, :feedback].each do |option|
|
132
135
|
expect(hash[option]).to eq config[option]
|
133
136
|
end
|
134
137
|
end
|
@@ -28,7 +28,7 @@ describe Honeybadger do
|
|
28
28
|
it "prints environment info on a failed notification without a body" do
|
29
29
|
reset_config
|
30
30
|
stub_verbose_log
|
31
|
-
stub_http(:response =>
|
31
|
+
stub_http(:response => Net::HTTPError, :body => nil)
|
32
32
|
Honeybadger.should_receive(:write_verbose_log).with(/Environment Info:/)
|
33
33
|
Honeybadger.should_not_receive(:write_verbose_log).with(/Response from Honeybadger:/, anything)
|
34
34
|
send_notice
|
@@ -46,9 +46,32 @@ describe Honeybadger do
|
|
46
46
|
it "prints environment info and response on a failure with a body" do
|
47
47
|
reset_config
|
48
48
|
stub_verbose_log
|
49
|
-
stub_http(:response =>
|
49
|
+
stub_http(:response => Net::HTTPError)
|
50
50
|
Honeybadger.should_receive(:write_verbose_log).with(/Environment Info:/)
|
51
51
|
Honeybadger.should_receive(:write_verbose_log).with(/Response from Honeybadger:/)
|
52
52
|
send_notice
|
53
53
|
end
|
54
|
+
|
55
|
+
context "429 error response" do
|
56
|
+
let(:failure_class) do
|
57
|
+
if RUBY_VERSION !~ /^1/
|
58
|
+
'Net::HTTPTooManyRequests'
|
59
|
+
else
|
60
|
+
'Net::HTTPClientError'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
before do
|
65
|
+
reset_config
|
66
|
+
stub_verbose_log
|
67
|
+
stub_request(:post, /api\.honeybadger\.io\/v1\/notices/).to_return(:status => 429, :body => '{"error":"something went wrong"}')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "logs the response" do
|
71
|
+
Honeybadger.should_receive(:write_verbose_log).with(/Failure: #{failure_class}/, :error)
|
72
|
+
Honeybadger.should_receive(:write_verbose_log).with(/Environment Info:/)
|
73
|
+
Honeybadger.should_receive(:write_verbose_log).with(/something went wrong/)
|
74
|
+
Honeybadger.notify(RuntimeError.new('oops!'))
|
75
|
+
end
|
76
|
+
end
|
54
77
|
end
|
@@ -95,6 +95,16 @@ describe Honeybadger::Notice do
|
|
95
95
|
expect(notice.hostname).to eq 'asdf'
|
96
96
|
end
|
97
97
|
|
98
|
+
it "defaults api key to configuration" do
|
99
|
+
notice = build_notice
|
100
|
+
expect(notice.api_key).to eq 'abc123def456'
|
101
|
+
end
|
102
|
+
|
103
|
+
it "sets the api key" do
|
104
|
+
notice = build_notice({ :api_key => 'asdf' })
|
105
|
+
expect(notice.api_key).to eq 'asdf'
|
106
|
+
end
|
107
|
+
|
98
108
|
context "custom fingerprint" do
|
99
109
|
it "includes nil fingerprint when no fingerprint is specified" do
|
100
110
|
notice = build_notice
|
@@ -303,6 +313,56 @@ describe Honeybadger::Notice do
|
|
303
313
|
assert_filters_hash(:session_data)
|
304
314
|
end
|
305
315
|
|
316
|
+
describe 'url' do
|
317
|
+
let(:params_filters) { [] }
|
318
|
+
let(:notice) { build_notice(:params_filters => params_filters, :url => url) }
|
319
|
+
|
320
|
+
context 'filtered params in query' do
|
321
|
+
let(:params_filters) { [:bar] }
|
322
|
+
let(:url) { 'https://www.honeybadger.io/?foo=1&bar=2&baz=3' }
|
323
|
+
|
324
|
+
it 'filters query' do
|
325
|
+
expect(notice.url).to eq 'https://www.honeybadger.io/?foo=1&bar=[FILTERED]&baz=3'
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'malformed query' do
|
330
|
+
let(:url) { 'https://www.honeybadger.io/?foobar12' }
|
331
|
+
|
332
|
+
it 'maintains query' do
|
333
|
+
expect(notice.url).to eq url
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
context 'no query' do
|
338
|
+
let(:url) { 'https://www.honeybadger.io' }
|
339
|
+
|
340
|
+
it 'keeps original URL' do
|
341
|
+
expect(notice.url).to eq url
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
context 'malformed url' do
|
346
|
+
let(:url) { 'http s ! honeybadger' }
|
347
|
+
|
348
|
+
before do
|
349
|
+
expect { URI.parse(url) }.to raise_error
|
350
|
+
end
|
351
|
+
|
352
|
+
it 'keeps original URL' do
|
353
|
+
expect(notice.url).to eq url
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
context 'complex url' do
|
358
|
+
let(:url) { 'https://foo:bar@www.honeybadger.io:123/asdf/?foo=1&bar=2&baz=3' }
|
359
|
+
|
360
|
+
it 'keeps original URL' do
|
361
|
+
expect(notice.url).to eq url
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
306
366
|
it "removes rack.request.form_vars" do
|
307
367
|
original = {
|
308
368
|
"rack.request.form_vars" => "story%5Btitle%5D=The+TODO+label",
|
@@ -559,14 +619,20 @@ describe Honeybadger::Notice do
|
|
559
619
|
end
|
560
620
|
|
561
621
|
def assert_filters_hash(attribute)
|
562
|
-
filters = ["abc", :def]
|
622
|
+
filters = ["abc", :def, /private/, /^foo_.*$/]
|
563
623
|
original = { 'abc' => "123", 'def' => "456", 'ghi' => "789", 'nested' => { 'abc' => '100' },
|
564
|
-
'something_with_abc' => 'match the entire string'
|
624
|
+
'something_with_abc' => 'match the entire string', 'private_param' => 'prra',
|
625
|
+
'foo_param' => 'bar', 'not_foo_param' => 'baz', 'nested_foo' => { 'foo_nested' => 'bla'} }
|
565
626
|
filtered = { 'abc' => "[FILTERED]",
|
566
627
|
'def' => "[FILTERED]",
|
567
628
|
'something_with_abc' => "match the entire string",
|
568
629
|
'ghi' => "789",
|
569
|
-
'nested' => { 'abc' => '[FILTERED]' }
|
630
|
+
'nested' => { 'abc' => '[FILTERED]' },
|
631
|
+
'private_param' => '[FILTERED]',
|
632
|
+
'foo_param' => '[FILTERED]',
|
633
|
+
'not_foo_param' => 'baz',
|
634
|
+
'nested_foo' => { 'foo_nested' => '[FILTERED]'}
|
635
|
+
}
|
570
636
|
|
571
637
|
notice = build_notice(:params_filters => filters, attribute => original)
|
572
638
|
|
@@ -1,27 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Honeybadger::Sender do
|
4
|
-
before
|
4
|
+
before { reset_config }
|
5
5
|
|
6
|
-
|
7
|
-
stub_request(:post, /api\.honeybadger\.io/)
|
6
|
+
before do
|
7
|
+
stub_request(:post, /api\.honeybadger\.io\/v1\/notices/).to_return(:body => '{"id":"123"}')
|
8
|
+
end
|
9
|
+
|
10
|
+
it "makes a single request when sending notices" do
|
8
11
|
Honeybadger.notify(RuntimeError.new('oops!'))
|
9
12
|
assert_requested :post, 'https://api.honeybadger.io/v1/notices/', :times => 1
|
10
13
|
end
|
11
14
|
|
12
15
|
it "posts to Honeybadger when using an HTTP proxy" do
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
url = "http://api.honeybadger.io:80#{Honeybadger::Sender::NOTICES_URI}"
|
18
|
-
uri = URI.parse(url)
|
16
|
+
http = stub_http
|
17
|
+
proxy = double(:new => http)
|
18
|
+
Net::HTTP.stub(:Proxy).and_return(proxy)
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
Faraday.should_receive(:new).
|
24
|
-
with(hash_including(:proxy => { :uri => 'https://some.host:88', :user => 'login', :password => 'passwd' })).and_return(http)
|
20
|
+
http.should_receive(:post).with(Honeybadger::Sender::NOTICES_URI, kind_of(String), Honeybadger::HEADERS.merge({ 'X-API-Key' => 'abc123'}))
|
21
|
+
Net::HTTP.should_receive(:Proxy).with('some.host', 88, 'login', 'passwd')
|
25
22
|
|
26
23
|
send_exception(:proxy_host => 'some.host',
|
27
24
|
:proxy_port => 88,
|
@@ -36,27 +33,47 @@ describe Honeybadger::Sender do
|
|
36
33
|
end
|
37
34
|
|
38
35
|
it "returns nil on failed posting" do
|
39
|
-
stub_http(:response =>
|
36
|
+
stub_http(:response => Net::HTTPError)
|
40
37
|
expect(send_exception(:secure => false)).to be_nil
|
41
38
|
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
40
|
+
describe '#api_key' do
|
41
|
+
context 'api_key is missing' do
|
42
|
+
it "logs missing API key and return nil" do
|
43
|
+
sender = build_sender(:api_key => nil)
|
44
|
+
sender.should_receive(:log).with(:error, /API key/)
|
45
|
+
expect(send_exception(:sender => sender, :secure => false)).to be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'notice is a hash' do
|
50
|
+
it 'uses api_key from hash when present' do
|
51
|
+
sender = build_sender(:api_key => 'asdf')
|
52
|
+
send_exception(:sender => sender, :notice => { 'api_key' => 'zxcv' })
|
53
|
+
assert_requested :post, 'https://api.honeybadger.io/v1/notices/', :times => 1, :headers => { 'x-api-key' => 'zxcv' }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'notice is a Honeybadger::Notice' do
|
58
|
+
it 'uses api_key from notice when present' do
|
59
|
+
sender = build_sender(:api_key => 'asdf')
|
60
|
+
send_exception(:sender => sender, :notice => Honeybadger::Notice.new(:api_key => 'zxcv'))
|
61
|
+
assert_requested :post, 'https://api.honeybadger.io/v1/notices/', :times => 1, :headers => { 'x-api-key' => 'zxcv' }
|
62
|
+
end
|
63
|
+
end
|
47
64
|
end
|
48
65
|
|
49
66
|
it "logs success" do
|
50
67
|
stub_http
|
51
68
|
sender = build_sender
|
52
|
-
sender.should_receive(:log).with(:debug, /Success/, kind_of(
|
69
|
+
sender.should_receive(:log).with(:debug, /Success/, kind_of(Net::HTTPSuccess), kind_of(String))
|
53
70
|
send_exception(:sender => sender, :secure => false)
|
54
71
|
end
|
55
72
|
|
56
73
|
it "logs failure" do
|
57
|
-
stub_http(:response =>
|
74
|
+
stub_http(:response => Net::HTTPServerError.new('1.2', '500', 'Internal Error'))
|
58
75
|
sender = build_sender
|
59
|
-
sender.should_receive(:log).with(:error, /Failure/, kind_of(
|
76
|
+
sender.should_receive(:log).with(:error, /Failure/, kind_of(Net::HTTPServerError), kind_of(String))
|
60
77
|
send_exception(:sender => sender, :secure => false)
|
61
78
|
end
|
62
79
|
|
@@ -64,24 +81,28 @@ describe Honeybadger::Sender do
|
|
64
81
|
# TODO: Figure out why nested groups aren't running
|
65
82
|
context "HTTP connection setup problems" do
|
66
83
|
it "should not be rescued" do
|
67
|
-
|
68
|
-
|
84
|
+
proxy = double()
|
85
|
+
proxy.stub(:new).and_raise(NoMemoryError)
|
86
|
+
Net::HTTP.stub(:Proxy).and_return(proxy)
|
87
|
+
expect { build_sender.send(:setup_http_connection) }.to raise_error(NoMemoryError)
|
69
88
|
end
|
70
89
|
|
71
90
|
it "should be logged" do
|
72
|
-
|
91
|
+
proxy = double()
|
92
|
+
proxy.stub(:new).and_raise(RuntimeError)
|
93
|
+
Net::HTTP.stub(:Proxy).and_return(proxy)
|
73
94
|
|
74
95
|
sender = build_sender
|
75
96
|
sender.should_receive(:log).with(:error, /Failure initializing the HTTP connection/)
|
76
97
|
|
77
|
-
expect { sender.send(:
|
98
|
+
expect { sender.send(:setup_http_connection) }.to raise_error(RuntimeError)
|
78
99
|
end
|
79
100
|
end
|
80
101
|
|
81
102
|
context "unexpected exception sending problems" do
|
82
103
|
it "should be logged" do
|
83
104
|
sender = build_sender
|
84
|
-
sender.should_receive(:
|
105
|
+
sender.should_receive(:setup_http_connection).and_raise(RuntimeError)
|
85
106
|
|
86
107
|
sender.should_receive(:log).with(:error, /Error/)
|
87
108
|
sender.send_to_honeybadger("stuff")
|
@@ -89,7 +110,7 @@ describe Honeybadger::Sender do
|
|
89
110
|
|
90
111
|
it "returns nil no matter what" do
|
91
112
|
sender = build_sender
|
92
|
-
sender.should_receive(:
|
113
|
+
sender.should_receive(:setup_http_connection).and_raise(LocalJumpError)
|
93
114
|
|
94
115
|
expect { sender.send_to_honeybadger("stuff").should be_nil }.not_to raise_error
|
95
116
|
end
|
@@ -127,34 +148,32 @@ describe Honeybadger::Sender do
|
|
127
148
|
http = stub_http
|
128
149
|
url = "http://api.honeybadger.io:80#{Honeybadger::Sender::NOTICES_URI}"
|
129
150
|
uri = URI.parse(url)
|
130
|
-
post
|
131
|
-
http.should_receive(:post).and_yield(post)
|
132
|
-
post.should_receive(:url).with(uri.path)
|
151
|
+
http.should_receive(:post).with(uri.path, anything, Honeybadger::HEADERS.merge({ 'X-API-Key' => 'abc123'}))
|
133
152
|
send_exception(:secure => false)
|
134
153
|
end
|
135
154
|
|
136
155
|
it "post to the right path for ssl" do
|
137
156
|
http = stub_http
|
138
|
-
post
|
139
|
-
http.should_receive(:post).and_yield(post)
|
140
|
-
post.should_receive(:url).with(Honeybadger::Sender::NOTICES_URI)
|
157
|
+
http.should_receive(:post).with(Honeybadger::Sender::NOTICES_URI, anything, Honeybadger::HEADERS.merge({ 'X-API-Key' => 'abc123'}))
|
141
158
|
send_exception(:secure => true)
|
142
159
|
end
|
143
160
|
|
144
161
|
it "verifies the SSL peer when the use_ssl option is set to true" do
|
145
162
|
url = "https://api.honeybadger.io#{Honeybadger::Sender::NOTICES_URI}"
|
163
|
+
uri = URI.parse(url)
|
146
164
|
|
147
|
-
real_http =
|
165
|
+
real_http = Net::HTTP.new(uri.host, uri.port)
|
148
166
|
real_http.stub(:post => nil)
|
149
|
-
|
167
|
+
proxy = double(:new => real_http)
|
168
|
+
Net::HTTP.stub(:Proxy => proxy)
|
150
169
|
|
151
170
|
File.stub(:exist?).with(OpenSSL::X509::DEFAULT_CERT_FILE).and_return(false)
|
152
171
|
|
153
172
|
send_exception(:secure => true)
|
154
173
|
|
155
|
-
expect(real_http.
|
156
|
-
expect(real_http.
|
157
|
-
expect(real_http.
|
174
|
+
expect(real_http.use_ssl?).to be_true
|
175
|
+
expect(real_http.verify_mode).to eq OpenSSL::SSL::VERIFY_PEER
|
176
|
+
expect(real_http.ca_file).to eq Honeybadger.configuration.local_cert_path
|
158
177
|
end
|
159
178
|
|
160
179
|
it "uses the default DEFAULT_CERT_FILE if asked to" do
|
@@ -169,61 +188,65 @@ describe Honeybadger::Sender do
|
|
169
188
|
|
170
189
|
expect(sender.use_system_ssl_cert_chain?).to be_true
|
171
190
|
|
172
|
-
http
|
173
|
-
expect(http.
|
191
|
+
http = sender.send(:setup_http_connection)
|
192
|
+
expect(http.ca_file).not_to eq Honeybadger.configuration.local_cert_path
|
174
193
|
end
|
175
194
|
|
176
195
|
it "verifies the connection when the use_ssl option is set (VERIFY_PEER)" do
|
177
196
|
sender = build_sender(:secure => true)
|
178
|
-
http = sender.send(:
|
179
|
-
expect(http.
|
197
|
+
http = sender.send(:setup_http_connection)
|
198
|
+
expect(http.verify_mode).to eq OpenSSL::SSL::VERIFY_PEER
|
180
199
|
end
|
181
200
|
|
182
201
|
it "uses the default cert (OpenSSL::X509::DEFAULT_CERT_FILE) only if explicitly told to" do
|
183
202
|
sender = build_sender(:secure => true)
|
184
|
-
http = sender.send(:
|
203
|
+
http = sender.send(:setup_http_connection)
|
185
204
|
|
186
|
-
expect(http.
|
205
|
+
expect(http.ca_file).to eq Honeybadger.configuration.local_cert_path
|
187
206
|
|
188
207
|
File.stub(:exist?).with(OpenSSL::X509::DEFAULT_CERT_FILE).and_return(true)
|
189
208
|
sender = build_sender(:secure => true, :use_system_ssl_cert_chain => true)
|
190
|
-
http = sender.send(:
|
209
|
+
http = sender.send(:setup_http_connection)
|
191
210
|
|
192
|
-
expect(http.
|
193
|
-
expect(http.
|
211
|
+
expect(http.ca_file).not_to eq Honeybadger.configuration.local_cert_path
|
212
|
+
expect(http.ca_file).to eq OpenSSL::X509::DEFAULT_CERT_FILE
|
194
213
|
end
|
195
214
|
|
196
215
|
it "uses ssl if secure" do
|
197
216
|
sender = build_sender(:secure => true)
|
198
|
-
http = sender.send(:
|
217
|
+
http = sender.send(:setup_http_connection)
|
199
218
|
expect(http.port).to eq 443
|
200
219
|
end
|
201
220
|
|
202
221
|
it "does not use ssl if not secure" do
|
203
222
|
sender = build_sender(:secure => false)
|
204
|
-
http = sender.send(:
|
223
|
+
http = sender.send(:setup_http_connection)
|
205
224
|
expect(http.port).to eq 80
|
206
225
|
end
|
207
226
|
end
|
208
227
|
|
209
228
|
context "network timeouts" do
|
210
229
|
it "default the open timeout to 2 seconds" do
|
211
|
-
|
230
|
+
http = stub_http
|
231
|
+
http.should_receive(:open_timeout=).with(2)
|
212
232
|
send_exception
|
213
233
|
end
|
214
234
|
|
215
235
|
it "default the read timeout to 5 seconds" do
|
216
|
-
|
236
|
+
http = stub_http
|
237
|
+
http.should_receive(:read_timeout=).with(5)
|
217
238
|
send_exception
|
218
239
|
end
|
219
240
|
|
220
241
|
it "allow override of the open timeout" do
|
221
|
-
|
242
|
+
http = stub_http
|
243
|
+
http.should_receive(:open_timeout=).with(4)
|
222
244
|
send_exception(:http_open_timeout => 4)
|
223
245
|
end
|
224
246
|
|
225
247
|
it "allow override of the read timeout" do
|
226
|
-
|
248
|
+
http = stub_http
|
249
|
+
http.should_receive(:read_timeout=).with(10)
|
227
250
|
send_exception(:http_read_timeout => 10)
|
228
251
|
end
|
229
252
|
end
|