honeybadger 1.9.5 → 1.10.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|