honeybadger 1.10.3 → 1.11.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +10 -0
  3. data/CHANGELOG.md +17 -10
  4. data/Gemfile.lock +1 -1
  5. data/features/rails.feature +6 -4
  6. data/features/step_definitions/rails_steps.rb +8 -0
  7. data/features/support/rails.rb +5 -0
  8. data/gemfiles/rack.gemfile.lock +1 -1
  9. data/gemfiles/rails2.3.gemfile.lock +1 -1
  10. data/gemfiles/rails3.0.gemfile.lock +1 -1
  11. data/gemfiles/rails3.1.gemfile.lock +1 -1
  12. data/gemfiles/rails3.2.gemfile.lock +1 -1
  13. data/gemfiles/rails4.gemfile.lock +1 -1
  14. data/gemfiles/rails4_cap3.gemfile +13 -0
  15. data/gemfiles/rails4_cap3.gemfile.lock +204 -0
  16. data/gemfiles/rake.gemfile.lock +1 -1
  17. data/gemfiles/sinatra.gemfile.lock +1 -1
  18. data/honeybadger.gemspec +7 -4
  19. data/lib/honeybadger.rb +14 -1
  20. data/lib/honeybadger/capistrano.rb +4 -45
  21. data/lib/honeybadger/capistrano/legacy.rb +45 -0
  22. data/lib/honeybadger/capistrano/tasks.rake +67 -0
  23. data/lib/honeybadger/configuration.rb +2 -2
  24. data/lib/honeybadger/monitor/worker.rb +1 -1
  25. data/lib/honeybadger/notice.rb +10 -1
  26. data/lib/honeybadger/rack.rb +1 -0
  27. data/lib/honeybadger/rails.rb +8 -0
  28. data/lib/honeybadger/railtie.rb +1 -7
  29. data/lib/honeybadger/stats.rb +1 -1
  30. data/lib/honeybadger/templates/{feedback_form.html.erb → feedback_form.erb} +12 -9
  31. data/lib/honeybadger/user_feedback.rb +47 -17
  32. data/lib/honeybadger_tasks.rb +3 -3
  33. data/lib/rails/generators/honeybadger/honeybadger_generator.rb +1 -2
  34. data/spec/honeybadger/capistrano_spec.rb +26 -23
  35. data/spec/honeybadger/configuration_spec.rb +25 -21
  36. data/spec/honeybadger/notice_spec.rb +30 -37
  37. data/spec/honeybadger/notifier_spec.rb +60 -4
  38. data/spec/honeybadger/rack_spec.rb +1 -0
  39. data/spec/honeybadger/user_feedback_spec.rb +29 -4
  40. data/spec/honeybadger_tasks_spec.rb +13 -4
  41. metadata +9 -6
  42. data/spec/honeybadger/stats_spec.rb +0 -57
@@ -17,12 +17,12 @@ module HoneybadgerTasks
17
17
  def self.deploy(opts = {})
18
18
  api_key = opts.delete(:api_key) || Honeybadger.configuration.api_key
19
19
  unless api_key =~ /\S/
20
- puts "I don't seem to be configured with an API key. Please check your configuration."
20
+ $stderr.puts "I don't seem to be configured with an API key. Please check your configuration."
21
21
  return false
22
22
  end
23
23
 
24
24
  unless opts[:environment] =~ /\S/
25
- puts "I don't know to which environment you are deploying (use the TO=production option)."
25
+ $stderr.puts "I don't know to which environment you are deploying (use the TO=production option)."
26
26
  return false
27
27
  end
28
28
 
@@ -60,7 +60,7 @@ module HoneybadgerTasks
60
60
  puts "Succesfully recorded deployment"
61
61
  return true
62
62
  else
63
- puts response.body
63
+ $stderr.puts "Error recording deployment: #{response.class} -- #{response.body || 'no response'}"
64
64
  return false
65
65
  end
66
66
  end
@@ -36,9 +36,8 @@ class HoneybadgerGenerator < Rails::Generators::Base
36
36
 
37
37
  def append_capistrano_hook
38
38
  if File.exists?('config/deploy.rb') && File.exists?('Capfile')
39
- append_file('config/deploy.rb', <<-HOOK)
39
+ append_file('Capfile', <<-HOOK)
40
40
 
41
- require './config/boot'
42
41
  require 'honeybadger/capistrano'
43
42
  HOOK
44
43
  end
@@ -1,33 +1,36 @@
1
1
  require 'spec_helper'
2
+ require 'capistrano'
2
3
 
3
- require 'capistrano/configuration'
4
- require 'honeybadger/capistrano'
4
+ if defined?(Capistrano::Configuration.instance)
5
+ describe 'Honeybadger::Capistrano' do
6
+ require 'capistrano/configuration'
7
+ require 'honeybadger/capistrano'
5
8
 
6
- describe Honeybadger::Capistrano do
7
- before(:each) do
8
- reset_config
9
+ before { reset_config }
9
10
 
10
- @configuration = Capistrano::Configuration.new
11
- Honeybadger::Capistrano.load_into(@configuration)
12
- @configuration.dry_run = true
13
- end
11
+ before(:each) do
12
+ @configuration = Capistrano::Configuration.new
13
+ Honeybadger::Capistrano.load_into(@configuration)
14
+ @configuration.dry_run = true
15
+ end
14
16
 
15
- it "defines honeybadger:deploy task" do
16
- expect(@configuration.find_task('honeybadger:deploy')).not_to be_nil
17
- end
17
+ it "defines honeybadger:deploy task" do
18
+ expect(@configuration.find_task('honeybadger:deploy')).not_to be_nil
19
+ end
18
20
 
19
- it "logs when calling honeybadger:deploy task" do
20
- @configuration.set(:current_revision, '084505b1c0e0bcf1526e673bb6ac99fbcb18aecc')
21
- @configuration.set(:repository, 'repository')
22
- @configuration.set(:current_release, '/home/deploy/rails_app/honeybadger')
23
- io = StringIO.new
24
- logger = Capistrano::Logger.new(:output => io)
25
- logger.level = Capistrano::Logger::MAX_LEVEL
21
+ it "logs when calling honeybadger:deploy task" do
22
+ @configuration.set(:current_revision, '084505b1c0e0bcf1526e673bb6ac99fbcb18aecc')
23
+ @configuration.set(:repository, 'repository')
24
+ @configuration.set(:current_release, '/home/deploy/rails_app/honeybadger')
25
+ io = StringIO.new
26
+ logger = Capistrano::Logger.new(:output => io)
27
+ logger.level = Capistrano::Logger::MAX_LEVEL
26
28
 
27
- @configuration.logger = logger
28
- @configuration.find_and_execute_task('honeybadger:deploy')
29
+ @configuration.logger = logger
30
+ @configuration.find_and_execute_task('honeybadger:deploy')
29
31
 
30
- expect(io.string).to include '** Notifying Honeybadger of Deploy'
31
- expect(io.string).to include '** Honeybadger Notification Complete'
32
+ expect(io.string).to include '** Notifying Honeybadger of Deploy'
33
+ expect(io.string).to include '** Honeybadger Notification Complete'
34
+ end
32
35
  end
33
36
  end
@@ -3,6 +3,7 @@ require 'socket'
3
3
 
4
4
  describe Honeybadger::Configuration do
5
5
  it "provides default values" do
6
+ assert_config_default :api_key, nil
6
7
  assert_config_default :proxy_host, nil
7
8
  assert_config_default :proxy_port, nil
8
9
  assert_config_default :proxy_user, nil
@@ -206,29 +207,32 @@ describe Honeybadger::Configuration do
206
207
  expect(config.public?).to be_true
207
208
  end
208
209
 
209
- it "is not be public if the notices feature is missing" do
210
- config = Honeybadger::Configuration.new
211
- config.features = {}
212
- expect(config.public?).to be_false
213
- end
210
+ describe "#metrics?" do
211
+ let(:config) { Honeybadger::Configuration.new }
214
212
 
215
- it "sends metrics by default in a public environment" do
216
- config = Honeybadger::Configuration.new
217
- config.environment_name = 'production'
218
- expect(config.metrics?).to be_true
219
- end
213
+ context "when public" do
214
+ before { config.stub(:public?).and_return(true) }
220
215
 
221
- it "sends not send metrics when disabled" do
222
- config = Honeybadger::Configuration.new
223
- config.environment_name = 'production'
224
- config.metrics = false
225
- expect(config.metrics?).to be_false
226
- end
216
+ it "sends metrics by default" do
217
+ expect(config.metrics?).to be_true
218
+ end
227
219
 
228
- it "sends not send metrics in a development environment" do
229
- config = Honeybadger::Configuration.new
230
- config.environment_name = 'development'
231
- expect(config.metrics?).to be_false
220
+ context "when disabled" do
221
+ before { config.metrics = false }
222
+
223
+ it "does not send metrics" do
224
+ expect(config.metrics?).to be_false
225
+ end
226
+ end
227
+ end
228
+
229
+ context "when not public" do
230
+ before { config.stub(:public?).and_return(false) }
231
+
232
+ it "does not send metrics" do
233
+ expect(config.metrics?).to be_false
234
+ end
235
+ end
232
236
  end
233
237
 
234
238
  it "uses the assigned logger if set" do
@@ -237,7 +241,7 @@ describe Honeybadger::Configuration do
237
241
  expect(config.logger).to eq "CUSTOM LOGGER"
238
242
  end
239
243
 
240
- it 'gives a new instance if non defined' do
244
+ it "gives a new instance if non defined" do
241
245
  Honeybadger.configuration = nil
242
246
  expect(Honeybadger.configuration).to be_a Honeybadger::Configuration
243
247
  end
@@ -14,15 +14,6 @@ describe Honeybadger::Notice do
14
14
  Honeybadger::Notice.new(configuration.merge(args))
15
15
  end
16
16
 
17
- def stub_request(attrs = {})
18
- double('request', { :parameters => { 'one' => 'two' },
19
- :protocol => 'http',
20
- :host => 'some.host',
21
- :request_uri => '/some/uri',
22
- :session => { :to_hash => { 'a' => 'b' } },
23
- :env => { 'three' => 'four' } }.update(attrs))
24
- end
25
-
26
17
  context '#deliver' do
27
18
  context 'sender is configured' do
28
19
  it "delivers to sender" do
@@ -313,53 +304,55 @@ describe Honeybadger::Notice do
313
304
  assert_filters_hash(:session_data)
314
305
  end
315
306
 
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' }
307
+ context 'filtered parameters in query string' do
308
+ let(:params_filters) { [:foo, :bar] }
323
309
 
310
+ describe '#url' do
311
+ let(:notice) { build_notice(:params_filters => params_filters, :url => 'https://www.honeybadger.io/?foo=1&bar=2&baz=3') }
324
312
  it 'filters query' do
325
- expect(notice.url).to eq 'https://www.honeybadger.io/?foo=1&bar=[FILTERED]&baz=3'
313
+ expect(notice.url).to eq 'https://www.honeybadger.io/?foo=[FILTERED]&bar=[FILTERED]&baz=3'
326
314
  end
327
315
  end
328
316
 
329
- context 'malformed query' do
330
- let(:url) { 'https://www.honeybadger.io/?foobar12' }
317
+ describe '#cgi_data' do
318
+ let(:cgi_data) { { 'QUERY_STRING' => 'foo=1&bar=2&baz=3', 'ORIGINAL_FULLPATH' => '/?foo=1&bar=2&baz=3' } }
319
+ let(:notice) { build_notice(:params_filters => params_filters, :cgi_data => cgi_data) }
320
+
321
+ subject { notice.cgi_data }
331
322
 
332
- it 'maintains query' do
333
- expect(notice.url).to eq url
323
+ it 'filters QUERY_STRING key' do
324
+ expect(subject['QUERY_STRING']).to eq 'foo=[FILTERED]&bar=[FILTERED]&baz=3'
334
325
  end
326
+
327
+ it 'filters ORIGINAL_FULLPATH key' do
328
+ expect(subject['ORIGINAL_FULLPATH']).to eq '/?foo=[FILTERED]&bar=[FILTERED]&baz=3'
329
+ end
330
+ end
331
+ end
332
+
333
+ describe '#filter_url' do
334
+ let(:notice) { build_notice(:params_filters => [], :url => url) }
335
+ subject { notice.send(:filter_url, url) }
336
+
337
+ context 'malformed query' do
338
+ let(:url) { 'https://www.honeybadger.io/?foobar12' }
339
+ it { should eq url }
335
340
  end
336
341
 
337
342
  context 'no query' do
338
343
  let(:url) { 'https://www.honeybadger.io' }
339
-
340
- it 'keeps original URL' do
341
- expect(notice.url).to eq url
342
- end
344
+ it { should eq url }
343
345
  end
344
346
 
345
347
  context 'malformed url' do
346
348
  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
349
+ before { expect { URI.parse(url) }.to raise_error }
350
+ it { should eq url }
355
351
  end
356
352
 
357
353
  context 'complex url' do
358
354
  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
355
+ it { should eq url }
363
356
  end
364
357
  end
365
358
 
@@ -7,10 +7,6 @@ describe 'Honeybadger' do
7
7
  class ContinuedException < Exception
8
8
  end
9
9
 
10
- before(:each) do
11
- reset_config
12
- end
13
-
14
10
  def assert_sends(notice, notice_args)
15
11
  Honeybadger::Notice.should_receive(:new).with(hash_including(notice_args))
16
12
  Honeybadger.sender.should_receive(:send_to_honeybadger).with(notice)
@@ -24,6 +20,66 @@ describe 'Honeybadger' do
24
20
  Honeybadger.configure { |config| config.environment_name = 'development' }
25
21
  end
26
22
 
23
+ before(:each) { reset_config }
24
+
25
+ describe "#ping" do
26
+ let(:config) { Honeybadger::Configuration.new }
27
+ let(:sender) { double() }
28
+
29
+ let(:invoke_subject) { Honeybadger.ping(config) }
30
+ subject { invoke_subject }
31
+
32
+ before do
33
+ config.framework = 'Rails 4.1.0'
34
+ config.environment_name = 'production'
35
+ config.hostname = 'twix'
36
+ stub_const('Honeybadger::VERSION', '1.11.0')
37
+
38
+ Honeybadger.stub(:sender).and_return(sender)
39
+ end
40
+
41
+ context "configuration is public" do
42
+ before { config.stub(:public?).and_return(true) }
43
+
44
+ it "pings the sender" do
45
+ sender.should_receive(:ping).with(hash_including(:version => '1.11.0', :framework => 'Rails 4.1.0', :environment => 'production', :hostname => 'twix'))
46
+ invoke_subject
47
+ end
48
+
49
+ context "result is truthy" do
50
+ before { sender.should_receive(:ping).and_return(result) }
51
+
52
+ context "result does not contain features" do
53
+ let(:result) { {} }
54
+ it { should be_nil }
55
+ specify { expect { subject }.not_to change(config, :features) }
56
+ end
57
+
58
+ context "result contains features" do
59
+ let(:result) { {'features' => {'notices' => true, 'metrics' => true}} }
60
+ it { should eq result['features'] }
61
+ specify { expect { subject }.to change(config, :features).to(result['features']) }
62
+ end
63
+ end
64
+
65
+ context "result is falsey" do
66
+ before { sender.should_receive(:ping) }
67
+ it { should be_nil }
68
+ specify { expect { invoke_subject }.not_to change(config, :features) }
69
+ end
70
+ end
71
+
72
+ context "configuration is not public" do
73
+ before { config.stub(:public?).and_return(false) }
74
+ it { should be_nil }
75
+
76
+ it "doesn't attempt to ping sender" do
77
+ sender.should_not_receive(:ping)
78
+ invoke_subject
79
+ end
80
+ end
81
+ end
82
+
27
83
  it "yields and save a configuration when configuring" do
28
84
  yielded_configuration = nil
29
85
  Honeybadger.configure do |config|
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'rack'
2
3
 
3
4
  describe Honeybadger::Rack do
4
5
  it "calls the upstream app with the environment" do
@@ -12,11 +12,12 @@ describe Honeybadger::UserFeedback do
12
12
  let(:response) { Net::HTTP.get_response(URI.parse("http://example.com/")) }
13
13
 
14
14
  before do
15
+ reset_config
15
16
  ShamRack.mount(informer_app, "example.com")
16
17
  end
17
18
 
18
19
  context "feedback feature is disabled by ping" do
19
- it 'does not modify the output' do
20
+ it "does not modify the output" do
20
21
  expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
21
22
  end
22
23
  end
@@ -29,25 +30,49 @@ describe Honeybadger::UserFeedback do
29
30
  context "there is a honeybadger id" do
30
31
  let(:honeybadger_id) { 1 }
31
32
 
32
- it 'modifies output' do
33
+ it "modifies output" do
33
34
  rendered_length = informer_app.render_form(1).size
34
35
  expect(response.body).to match(/honeybadger_feedback_token/)
35
36
  expect(response["Content-Length"].to_i).to eq rendered_length
36
37
  end
37
38
 
39
+ context "a project root is configured" do
40
+ let(:tmp_dir) { File.expand_path('../../../tmp', __FILE__) }
41
+ let(:template_dir) { File.join(tmp_dir, 'lib', 'honeybadger', 'templates') }
42
+ let(:template_file) { File.join(template_dir, 'feedback_form.erb') }
43
+
44
+ before do
45
+ FileUtils.mkdir_p(template_dir)
46
+ FileUtils.rm_f(template_file)
47
+ Honeybadger.configure(true) do |config|
48
+ config.project_root = tmp_dir
49
+ end
50
+ end
51
+
52
+ context "custom template is implemented" do
53
+ before do
54
+ File.open(template_file, 'w') { |f| f.write 'custom feedback form' }
55
+ end
56
+
57
+ it "renders with custom template" do
58
+ expect(response.body).to match(/custom feedback form/)
59
+ end
60
+ end
61
+ end
62
+
38
63
  context "feedback feature is disabled by customer" do
39
64
  before do
40
65
  Honeybadger.configuration.feedback = false
41
66
  end
42
67
 
43
- it 'does not modify the output' do
68
+ it "does not modify the output" do
44
69
  expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
45
70
  end
46
71
  end
47
72
  end
48
73
 
49
74
  context "there is no honeybadger id" do
50
- it 'does not modify the output' do
75
+ it "does not modify the output" do
51
76
  expect(response.body).to eq '<!-- HONEYBADGER FEEDBACK -->'
52
77
  end
53
78
  end
@@ -17,14 +17,17 @@ describe HoneybadgerTasks do
17
17
  end
18
18
 
19
19
  context "being quiet" do
20
- before(:each) { HoneybadgerTasks.stub(:puts) }
20
+ before do
21
+ HoneybadgerTasks.stub(:puts)
22
+ $stderr.stub(:puts)
23
+ end
21
24
 
22
25
  context "in a configured project" do
23
26
  before(:each) { Honeybadger.configure { |config| config.api_key = "1234123412341234" } }
24
27
 
25
28
  context "on deploy({})" do
26
29
  it "complains about missing rails env" do
27
- HoneybadgerTasks.should_receive(:puts).with(/which environment/i)
30
+ $stderr.should_receive(:puts).with(/which environment/i)
28
31
  HoneybadgerTasks.deploy({})
29
32
  end
30
33
 
@@ -95,11 +98,17 @@ describe HoneybadgerTasks do
95
98
  end
96
99
 
97
100
  it "puts the response body on failure" do
98
- HoneybadgerTasks.should_receive(:puts).with("body")
101
+ $stderr.should_receive(:puts).with(/body/)
99
102
  @http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response('body'))
100
103
  HoneybadgerTasks.deploy(@options)
101
104
  end
102
105
 
106
+ it "puts the response class on failure" do
107
+ $stderr.should_receive(:puts).with(/Net::HTTPClientError/)
108
+ @http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response)
109
+ HoneybadgerTasks.deploy(@options)
110
+ end
111
+
103
112
  it "returns false on failure" do
104
113
  @http_proxy.should_receive(:request).with(anything).and_return(unsuccessful_response('body'))
105
114
  output = HoneybadgerTasks.deploy(@options)
@@ -148,7 +157,7 @@ describe HoneybadgerTasks do
148
157
 
149
158
  context "on deploy(:environment => 'staging')" do
150
159
  it "complains about missing api key" do
151
- HoneybadgerTasks.should_receive(:puts).with(/api key/i)
160
+ $stderr.should_receive(:puts).with(/api key/i)
152
161
  HoneybadgerTasks.deploy(:environment => "staging")
153
162
  end
154
163