honeybadger 1.0.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.
- data/Gemfile +13 -0
- data/Gemfile.lock +114 -0
- data/Guardfile +5 -0
- data/MIT-LICENSE +22 -0
- data/README.md +271 -0
- data/Rakefile +261 -0
- data/SUPPORTED_RAILS_VERSIONS +26 -0
- data/TESTING.md +33 -0
- data/features/metal.feature +18 -0
- data/features/rack.feature +56 -0
- data/features/rails.feature +211 -0
- data/features/rake.feature +27 -0
- data/features/sinatra.feature +29 -0
- data/features/step_definitions/file_steps.rb +10 -0
- data/features/step_definitions/metal_steps.rb +23 -0
- data/features/step_definitions/rack_steps.rb +23 -0
- data/features/step_definitions/rails_application_steps.rb +394 -0
- data/features/step_definitions/rake_steps.rb +17 -0
- data/features/support/env.rb +17 -0
- data/features/support/honeybadger_shim.rb.template +8 -0
- data/features/support/rails.rb +201 -0
- data/features/support/rake/Rakefile +68 -0
- data/features/support/terminal.rb +107 -0
- data/generators/honeybadger/honeybadger_generator.rb +94 -0
- data/generators/honeybadger/lib/insert_commands.rb +34 -0
- data/generators/honeybadger/lib/rake_commands.rb +24 -0
- data/generators/honeybadger/templates/capistrano_hook.rb +6 -0
- data/generators/honeybadger/templates/honeybadger_tasks.rake +25 -0
- data/generators/honeybadger/templates/initializer.rb +6 -0
- data/honeybadger.gemspec +109 -0
- data/lib/honeybadger.rb +162 -0
- data/lib/honeybadger/backtrace.rb +123 -0
- data/lib/honeybadger/capistrano.rb +43 -0
- data/lib/honeybadger/configuration.rb +273 -0
- data/lib/honeybadger/notice.rb +314 -0
- data/lib/honeybadger/rack.rb +55 -0
- data/lib/honeybadger/rails.rb +34 -0
- data/lib/honeybadger/rails/action_controller_catcher.rb +30 -0
- data/lib/honeybadger/rails/controller_methods.rb +69 -0
- data/lib/honeybadger/rails/middleware/exceptions_catcher.rb +29 -0
- data/lib/honeybadger/rails3_tasks.rb +84 -0
- data/lib/honeybadger/railtie.rb +45 -0
- data/lib/honeybadger/rake_handler.rb +65 -0
- data/lib/honeybadger/sender.rb +120 -0
- data/lib/honeybadger/shared_tasks.rb +36 -0
- data/lib/honeybadger/tasks.rb +82 -0
- data/lib/honeybadger_tasks.rb +65 -0
- data/lib/rails/generators/honeybadger/honeybadger_generator.rb +99 -0
- data/rails/init.rb +1 -0
- data/resources/README.md +34 -0
- data/resources/ca-bundle.crt +3376 -0
- data/script/integration_test.rb +38 -0
- data/test/test_helper.rb +143 -0
- data/test/unit/backtrace_test.rb +180 -0
- data/test/unit/capistrano_test.rb +34 -0
- data/test/unit/configuration_test.rb +201 -0
- data/test/unit/honeybadger_tasks_test.rb +163 -0
- data/test/unit/logger_test.rb +72 -0
- data/test/unit/notice_test.rb +406 -0
- data/test/unit/notifier_test.rb +245 -0
- data/test/unit/rack_test.rb +56 -0
- data/test/unit/rails/action_controller_catcher_test.rb +300 -0
- data/test/unit/rails_test.rb +35 -0
- data/test/unit/sender_test.rb +257 -0
- metadata +315 -0
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
require File.expand_path('../../../lib/honeybadger_tasks', __FILE__)
|
5
|
+
require 'fakeweb'
|
6
|
+
|
7
|
+
FakeWeb.allow_net_connect = false
|
8
|
+
|
9
|
+
class HoneybadgerTasksTest < Honeybadger::UnitTest
|
10
|
+
def successful_response(body = "")
|
11
|
+
response = Net::HTTPSuccess.new('1.2', '200', 'OK')
|
12
|
+
response.stubs(:body).returns(body)
|
13
|
+
return response
|
14
|
+
end
|
15
|
+
|
16
|
+
def unsuccessful_response(body = "")
|
17
|
+
response = Net::HTTPClientError.new('1.2', '200', 'OK')
|
18
|
+
response.stubs(:body).returns(body)
|
19
|
+
return response
|
20
|
+
end
|
21
|
+
|
22
|
+
context "being quiet" do
|
23
|
+
setup { HoneybadgerTasks.stubs(:puts) }
|
24
|
+
|
25
|
+
context "in a configured project" do
|
26
|
+
setup { Honeybadger.configure { |config| config.api_key = "1234123412341234" } }
|
27
|
+
|
28
|
+
context "on deploy({})" do
|
29
|
+
setup { @output = HoneybadgerTasks.deploy({}) }
|
30
|
+
|
31
|
+
before_should "complain about missing rails env" do
|
32
|
+
HoneybadgerTasks.expects(:puts).with(regexp_matches(/rails environment/i))
|
33
|
+
end
|
34
|
+
|
35
|
+
should "return false" do
|
36
|
+
assert !@output
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "given an optional HTTP proxy and valid options" do
|
41
|
+
setup do
|
42
|
+
@response = stub("response", :body => "stub body")
|
43
|
+
@http_proxy = stub("proxy", :request => @response)
|
44
|
+
@http_proxy_class = stub("proxy_class", :new => @http_proxy)
|
45
|
+
@post = stub("post", :set_form_data => nil)
|
46
|
+
|
47
|
+
@post.stubs(:[]=).with('X-API-Key', '1234123412341234').returns(true)
|
48
|
+
|
49
|
+
Net::HTTP.expects(:Proxy).
|
50
|
+
with(Honeybadger.configuration.proxy_host,
|
51
|
+
Honeybadger.configuration.proxy_port,
|
52
|
+
Honeybadger.configuration.proxy_user,
|
53
|
+
Honeybadger.configuration.proxy_pass).
|
54
|
+
returns(@http_proxy_class)
|
55
|
+
Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
|
56
|
+
|
57
|
+
@options = { :rails_env => "staging", :dry_run => false }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "performing a dry run" do
|
61
|
+
setup { @output = HoneybadgerTasks.deploy(@options.merge(:dry_run => true)) }
|
62
|
+
|
63
|
+
should "return true without performing any actual request" do
|
64
|
+
assert_equal true, @output
|
65
|
+
assert_received(@http_proxy, :request) do |expects|
|
66
|
+
expects.never
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "on deploy(options)" do
|
72
|
+
setup do
|
73
|
+
@output = HoneybadgerTasks.deploy(@options)
|
74
|
+
end
|
75
|
+
|
76
|
+
before_should "post to http://api.honeybadger.io:80/deploys.txt" do
|
77
|
+
@http_proxy_class.expects(:new).with("api.honeybadger.io", 80).returns(@http_proxy)
|
78
|
+
@post.expects(:set_form_data).with(kind_of(Hash))
|
79
|
+
@http_proxy.expects(:request).with(any_parameters).returns(successful_response)
|
80
|
+
end
|
81
|
+
|
82
|
+
before_should "use send the rails_env param" do
|
83
|
+
@post.expects(:set_form_data).
|
84
|
+
with(has_entries("deploy[rails_env]" => "staging"))
|
85
|
+
end
|
86
|
+
|
87
|
+
[:local_username, :scm_repository, :scm_revision].each do |key|
|
88
|
+
before_should "use send the #{key} param if it's passed in." do
|
89
|
+
@options[key] = "value"
|
90
|
+
@post.expects(:set_form_data).
|
91
|
+
with(has_entries("deploy[#{key}]" => "value"))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
before_should "puts the response body on success" do
|
96
|
+
HoneybadgerTasks.expects(:puts).with("body")
|
97
|
+
@http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
|
98
|
+
end
|
99
|
+
|
100
|
+
before_should "puts the response body on failure" do
|
101
|
+
HoneybadgerTasks.expects(:puts).with("body")
|
102
|
+
@http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
|
103
|
+
end
|
104
|
+
|
105
|
+
should "return false on failure", :before => lambda {
|
106
|
+
@http_proxy.expects(:request).with(any_parameters).returns(unsuccessful_response('body'))
|
107
|
+
} do
|
108
|
+
assert !@output
|
109
|
+
end
|
110
|
+
|
111
|
+
should "return true on success", :before => lambda {
|
112
|
+
@http_proxy.expects(:request).with(any_parameters).returns(successful_response('body'))
|
113
|
+
} do
|
114
|
+
assert @output
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "in a configured project with custom host" do
|
121
|
+
setup do
|
122
|
+
Honeybadger.configure do |config|
|
123
|
+
config.api_key = "1234123412341234"
|
124
|
+
config.host = "custom.host"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "on deploy(:rails_env => 'staging')" do
|
129
|
+
setup { @output = HoneybadgerTasks.deploy(:rails_env => "staging") }
|
130
|
+
|
131
|
+
before_should "post to the custom host" do
|
132
|
+
@post = stub("post", :set_form_data => nil)
|
133
|
+
@http_proxy = stub("proxy", :request => @response)
|
134
|
+
|
135
|
+
@post.stubs(:[]=).with('X-API-Key', '1234123412341234').returns(true)
|
136
|
+
|
137
|
+
@http_proxy_class = stub("proxy_class", :new => @http_proxy)
|
138
|
+
@http_proxy_class.expects(:new).with("custom.host", 80).returns(@http_proxy)
|
139
|
+
Net::HTTP.expects(:Proxy).with(any_parameters).returns(@http_proxy_class)
|
140
|
+
Net::HTTP::Post.expects(:new).with("/deploys.txt").returns(@post)
|
141
|
+
@post.expects(:set_form_data).with(kind_of(Hash))
|
142
|
+
@http_proxy.expects(:request).with(any_parameters).returns(successful_response)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context "when not configured" do
|
148
|
+
setup { Honeybadger.configure { |config| config.api_key = "" } }
|
149
|
+
|
150
|
+
context "on deploy(:rails_env => 'staging')" do
|
151
|
+
setup { @output = HoneybadgerTasks.deploy(:rails_env => "staging") }
|
152
|
+
|
153
|
+
before_should "complain about missing api key" do
|
154
|
+
HoneybadgerTasks.expects(:puts).with(regexp_matches(/api key/i))
|
155
|
+
end
|
156
|
+
|
157
|
+
should "return false" do
|
158
|
+
assert !@output
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class LoggerTest < Honeybadger::UnitTest
|
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
|
+
Honeybadger.sender.send_to_honeybadger('data')
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub_verbose_log
|
18
|
+
Honeybadger.stubs(:write_verbose_log)
|
19
|
+
end
|
20
|
+
|
21
|
+
def configure
|
22
|
+
Honeybadger.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
|
+
Honeybadger.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 Honeybadger:/
|
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 Honeybadger:/
|
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, '{}')
|
59
|
+
send_notice
|
60
|
+
assert_logged /Environment Info:/
|
61
|
+
assert_logged /Response from Honeybadger:/
|
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, '{}')
|
68
|
+
send_notice
|
69
|
+
assert_logged /Environment Info:/
|
70
|
+
assert_logged /Response from Honeybadger:/
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,406 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class NoticeTest < Honeybadger::UnitTest
|
5
|
+
include DefinesConstants
|
6
|
+
|
7
|
+
def configure
|
8
|
+
Honeybadger::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
|
+
Honeybadger::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
|
+
should "generate json from as_json template" do
|
28
|
+
notice = build_notice
|
29
|
+
hash = {'foo' => 'bar'}
|
30
|
+
notice.expects(:as_json).once.returns(hash)
|
31
|
+
json = notice.to_json
|
32
|
+
|
33
|
+
payload = nil
|
34
|
+
assert_nothing_raised do
|
35
|
+
payload = JSON.parse(json)
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_equal payload, hash
|
39
|
+
end
|
40
|
+
|
41
|
+
should "accept a project root" do
|
42
|
+
project_root = '/path/to/project'
|
43
|
+
notice = build_notice(:project_root => project_root)
|
44
|
+
assert_equal project_root, notice.project_root
|
45
|
+
end
|
46
|
+
|
47
|
+
should "accept a component" do
|
48
|
+
assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
|
49
|
+
end
|
50
|
+
|
51
|
+
should "alias the component as controller" do
|
52
|
+
assert_equal 'users_controller', build_notice(:controller => 'users_controller').component
|
53
|
+
assert_equal 'users_controller', build_notice(:component => 'users_controller').controller
|
54
|
+
end
|
55
|
+
|
56
|
+
should "accept a action" do
|
57
|
+
assert_equal 'index', build_notice(:action => 'index').action
|
58
|
+
end
|
59
|
+
|
60
|
+
should "accept a url" do
|
61
|
+
url = 'http://some.host/uri'
|
62
|
+
notice = build_notice(:url => url)
|
63
|
+
assert_equal url, notice.url
|
64
|
+
end
|
65
|
+
|
66
|
+
should "set the host name" do
|
67
|
+
notice = build_notice
|
68
|
+
assert_equal hostname, notice.hostname
|
69
|
+
end
|
70
|
+
|
71
|
+
should "accept a backtrace from an exception or hash" do
|
72
|
+
array = ["user.rb:34:in `crazy'"]
|
73
|
+
exception = build_exception
|
74
|
+
exception.set_backtrace array
|
75
|
+
backtrace = Honeybadger::Backtrace.parse(array)
|
76
|
+
notice_from_exception = build_notice(:exception => exception)
|
77
|
+
|
78
|
+
|
79
|
+
assert_equal backtrace,
|
80
|
+
notice_from_exception.backtrace,
|
81
|
+
"backtrace was not correctly set from an exception"
|
82
|
+
|
83
|
+
notice_from_hash = build_notice(:backtrace => array)
|
84
|
+
assert_equal backtrace,
|
85
|
+
notice_from_hash.backtrace,
|
86
|
+
"backtrace was not correctly set from a hash"
|
87
|
+
end
|
88
|
+
|
89
|
+
should "pass its backtrace filters for parsing" do
|
90
|
+
backtrace_array = ['my/file/backtrace:3']
|
91
|
+
exception = build_exception
|
92
|
+
exception.set_backtrace(backtrace_array)
|
93
|
+
Honeybadger::Backtrace.expects(:parse).with(backtrace_array, {:filters => 'foo'})
|
94
|
+
|
95
|
+
notice = Honeybadger::Notice.new({:exception => exception, :backtrace_filters => 'foo'})
|
96
|
+
end
|
97
|
+
|
98
|
+
should "set the error class from an exception or hash" do
|
99
|
+
assert_accepts_exception_attribute :error_class do |exception|
|
100
|
+
exception.class.name
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
should "set the error message from an exception or hash" do
|
105
|
+
assert_accepts_exception_attribute :error_message do |exception|
|
106
|
+
"#{exception.class.name}: #{exception.message}"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
should "accept parameters from a request or hash" do
|
111
|
+
parameters = { 'one' => 'two' }
|
112
|
+
notice_from_hash = build_notice(:parameters => parameters)
|
113
|
+
assert_equal notice_from_hash.parameters, parameters
|
114
|
+
end
|
115
|
+
|
116
|
+
should "accept session data from a session[:data] hash" do
|
117
|
+
data = { 'one' => 'two' }
|
118
|
+
notice = build_notice(:session => { :data => data })
|
119
|
+
assert_equal data, notice.session_data
|
120
|
+
end
|
121
|
+
|
122
|
+
should "accept session data from a session_data hash" do
|
123
|
+
data = { 'one' => 'two' }
|
124
|
+
notice = build_notice(:session_data => data)
|
125
|
+
assert_equal data, notice.session_data
|
126
|
+
end
|
127
|
+
|
128
|
+
should "accept an environment name" do
|
129
|
+
assert_equal 'development', build_notice(:environment_name => 'development').environment_name
|
130
|
+
end
|
131
|
+
|
132
|
+
should "accept CGI data from a hash" do
|
133
|
+
data = { 'string' => 'value' }
|
134
|
+
notice = build_notice(:cgi_data => data)
|
135
|
+
assert_equal data, notice.cgi_data, "should take CGI data from a hash"
|
136
|
+
end
|
137
|
+
|
138
|
+
should "accept notifier information" do
|
139
|
+
params = { :notifier_name => 'a name for a notifier',
|
140
|
+
:notifier_version => '1.0.5',
|
141
|
+
:notifier_url => 'http://notifiers.r.us/download' }
|
142
|
+
notice = build_notice(params)
|
143
|
+
assert_equal params[:notifier_name], notice.notifier_name
|
144
|
+
assert_equal params[:notifier_version], notice.notifier_version
|
145
|
+
assert_equal params[:notifier_url], notice.notifier_url
|
146
|
+
end
|
147
|
+
|
148
|
+
should "set sensible defaults without an exception" do
|
149
|
+
backtrace = Honeybadger::Backtrace.parse(build_backtrace_array)
|
150
|
+
notice = build_notice(:backtrace => build_backtrace_array)
|
151
|
+
|
152
|
+
assert_equal 'Notification', notice.error_message
|
153
|
+
assert_array_starts_with backtrace.lines, notice.backtrace.lines
|
154
|
+
assert_equal({}, notice.parameters)
|
155
|
+
assert_equal({}, notice.session_data)
|
156
|
+
end
|
157
|
+
|
158
|
+
should "use the caller as the backtrace for an exception without a backtrace" do
|
159
|
+
filters = Honeybadger::Configuration.new.backtrace_filters
|
160
|
+
backtrace = Honeybadger::Backtrace.parse(caller, :filters => filters)
|
161
|
+
notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
|
162
|
+
|
163
|
+
assert_array_starts_with backtrace.lines, notice.backtrace.lines
|
164
|
+
end
|
165
|
+
|
166
|
+
should "convert unserializable objects to strings" do
|
167
|
+
assert_serializes_hash(:parameters)
|
168
|
+
assert_serializes_hash(:cgi_data)
|
169
|
+
assert_serializes_hash(:session_data)
|
170
|
+
end
|
171
|
+
|
172
|
+
should "filter parameters" do
|
173
|
+
assert_filters_hash(:parameters)
|
174
|
+
end
|
175
|
+
|
176
|
+
should "filter cgi data" do
|
177
|
+
assert_filters_hash(:cgi_data)
|
178
|
+
end
|
179
|
+
|
180
|
+
should "filter session" do
|
181
|
+
assert_filters_hash(:session_data)
|
182
|
+
end
|
183
|
+
|
184
|
+
should "remove rack.request.form_vars" do
|
185
|
+
original = {
|
186
|
+
"rack.request.form_vars" => "story%5Btitle%5D=The+TODO+label",
|
187
|
+
"abc" => "123"
|
188
|
+
}
|
189
|
+
|
190
|
+
notice = build_notice(:cgi_data => original)
|
191
|
+
assert_equal({"abc" => "123"}, notice.cgi_data)
|
192
|
+
end
|
193
|
+
|
194
|
+
should "not send empty request data" do
|
195
|
+
notice = build_notice
|
196
|
+
assert_nil notice.url
|
197
|
+
assert_nil notice.controller
|
198
|
+
assert_nil notice.action
|
199
|
+
|
200
|
+
json = notice.to_json
|
201
|
+
payload = JSON.parse(json)
|
202
|
+
assert_nil payload['request']['url']
|
203
|
+
assert_nil payload['request']['component']
|
204
|
+
assert_nil payload['request']['action']
|
205
|
+
end
|
206
|
+
|
207
|
+
%w(url controller action).each do |var|
|
208
|
+
should "send a request if #{var} is present" do
|
209
|
+
notice = build_notice(var.to_sym => 'value')
|
210
|
+
json = notice.to_json
|
211
|
+
payload = JSON.parse(json)
|
212
|
+
assert_not_nil payload['request']
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
%w(parameters cgi_data session_data).each do |var|
|
217
|
+
should "send a request if #{var} is present" do
|
218
|
+
notice = build_notice(var.to_sym => { 'key' => 'value' })
|
219
|
+
json = notice.to_json
|
220
|
+
payload = JSON.parse(json)
|
221
|
+
assert_not_nil payload['request']
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
should "not ignore an exception not matching ignore filters" do
|
226
|
+
notice = build_notice(:error_class => 'ArgumentError',
|
227
|
+
:ignore => ['Argument'],
|
228
|
+
:ignore_by_filters => [lambda { |notice| false }])
|
229
|
+
assert !notice.ignore?
|
230
|
+
end
|
231
|
+
|
232
|
+
should "ignore an exception with a matching error class" do
|
233
|
+
notice = build_notice(:error_class => 'ArgumentError',
|
234
|
+
:ignore => [ArgumentError])
|
235
|
+
assert notice.ignore?
|
236
|
+
end
|
237
|
+
|
238
|
+
should "ignore an exception with a matching error class name" do
|
239
|
+
notice = build_notice(:error_class => 'ArgumentError',
|
240
|
+
:ignore => ['ArgumentError'])
|
241
|
+
assert notice.ignore?
|
242
|
+
end
|
243
|
+
|
244
|
+
should "ignore an exception with a matching filter" do
|
245
|
+
filter = lambda {|notice| notice.error_class == 'ArgumentError' }
|
246
|
+
notice = build_notice(:error_class => 'ArgumentError',
|
247
|
+
:ignore_by_filters => [filter])
|
248
|
+
assert notice.ignore?
|
249
|
+
end
|
250
|
+
|
251
|
+
should "not raise without an ignore list" do
|
252
|
+
notice = build_notice(:ignore => nil, :ignore_by_filters => nil)
|
253
|
+
assert_nothing_raised do
|
254
|
+
notice.ignore?
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
ignored_error_classes = %w(
|
259
|
+
ActiveRecord::RecordNotFound
|
260
|
+
AbstractController::ActionNotFound
|
261
|
+
ActionController::RoutingError
|
262
|
+
ActionController::InvalidAuthenticityToken
|
263
|
+
CGI::Session::CookieStore::TamperedWithCookie
|
264
|
+
ActionController::UnknownAction
|
265
|
+
)
|
266
|
+
|
267
|
+
ignored_error_classes.each do |ignored_error_class|
|
268
|
+
should "ignore #{ignored_error_class} error by default" do
|
269
|
+
notice = build_notice(:error_class => ignored_error_class)
|
270
|
+
assert notice.ignore?
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
should "act like a hash" do
|
275
|
+
notice = build_notice(:error_message => 'some message')
|
276
|
+
assert_equal notice.error_message, notice[:error_message]
|
277
|
+
end
|
278
|
+
|
279
|
+
should "return params on notice[:request][:params]" do
|
280
|
+
params = { 'one' => 'two' }
|
281
|
+
notice = build_notice(:parameters => params)
|
282
|
+
assert_equal params, notice[:request][:params]
|
283
|
+
end
|
284
|
+
|
285
|
+
should "ensure #to_hash is called on objects that support it" do
|
286
|
+
assert_nothing_raised do
|
287
|
+
build_notice(:session => { :object => stub(:to_hash => {}) })
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
should "ensure #to_ary is called on objects that support it" do
|
293
|
+
assert_nothing_raised do
|
294
|
+
build_notice(:session => { :object => stub(:to_ary => {}) })
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
should "extract data from a rack environment hash" do
|
299
|
+
url = "https://subdomain.happylane.com:100/test/file.rb?var=value&var2=value2"
|
300
|
+
parameters = { 'var' => 'value', 'var2' => 'value2' }
|
301
|
+
env = Rack::MockRequest.env_for(url)
|
302
|
+
|
303
|
+
notice = build_notice(:rack_env => env)
|
304
|
+
|
305
|
+
assert_equal url, notice.url
|
306
|
+
assert_equal parameters, notice.parameters
|
307
|
+
assert_equal 'GET', notice.cgi_data['REQUEST_METHOD']
|
308
|
+
end
|
309
|
+
|
310
|
+
should "extract data from a rack environment hash with action_dispatch info" do
|
311
|
+
params = { 'controller' => 'users', 'action' => 'index', 'id' => '7' }
|
312
|
+
env = Rack::MockRequest.env_for('/', { 'action_dispatch.request.parameters' => params })
|
313
|
+
|
314
|
+
notice = build_notice(:rack_env => env)
|
315
|
+
|
316
|
+
assert_equal params, notice.parameters
|
317
|
+
assert_equal params['controller'], notice.component
|
318
|
+
assert_equal params['action'], notice.action
|
319
|
+
end
|
320
|
+
|
321
|
+
should "extract session data from a rack environment" do
|
322
|
+
session_data = { 'something' => 'some value' }
|
323
|
+
env = Rack::MockRequest.env_for('/', 'rack.session' => session_data)
|
324
|
+
|
325
|
+
notice = build_notice(:rack_env => env)
|
326
|
+
|
327
|
+
assert_equal session_data, notice.session_data
|
328
|
+
end
|
329
|
+
|
330
|
+
should "prefer passed session data to rack session data" do
|
331
|
+
session_data = { 'something' => 'some value' }
|
332
|
+
env = Rack::MockRequest.env_for('/')
|
333
|
+
|
334
|
+
notice = build_notice(:rack_env => env, :session_data => session_data)
|
335
|
+
|
336
|
+
assert_equal session_data, notice.session_data
|
337
|
+
end
|
338
|
+
|
339
|
+
should "not allow infinite recursion" do
|
340
|
+
hash = {:a => :a}
|
341
|
+
hash[:hash] = hash
|
342
|
+
notice = Honeybadger::Notice.new(:parameters => hash)
|
343
|
+
assert_equal "[possible infinite recursion halted]", notice.parameters[:hash]
|
344
|
+
end
|
345
|
+
|
346
|
+
def assert_accepts_exception_attribute(attribute, args = {}, &block)
|
347
|
+
exception = build_exception
|
348
|
+
block ||= lambda { exception.send(attribute) }
|
349
|
+
value = block.call(exception)
|
350
|
+
|
351
|
+
notice_from_exception = build_notice(args.merge(:exception => exception))
|
352
|
+
|
353
|
+
assert_equal notice_from_exception.send(attribute),
|
354
|
+
value,
|
355
|
+
"#{attribute} was not correctly set from an exception"
|
356
|
+
|
357
|
+
notice_from_hash = build_notice(args.merge(attribute => value))
|
358
|
+
assert_equal notice_from_hash.send(attribute),
|
359
|
+
value,
|
360
|
+
"#{attribute} was not correctly set from a hash"
|
361
|
+
end
|
362
|
+
|
363
|
+
def assert_serializes_hash(attribute)
|
364
|
+
[File.open(__FILE__), Proc.new { puts "boo!" }, Module.new].each do |object|
|
365
|
+
hash = {
|
366
|
+
:strange_object => object,
|
367
|
+
:sub_hash => {
|
368
|
+
:sub_object => object
|
369
|
+
},
|
370
|
+
:array => [object]
|
371
|
+
}
|
372
|
+
notice = build_notice(attribute => hash)
|
373
|
+
hash = notice.send(attribute)
|
374
|
+
assert_equal object.to_s, hash[:strange_object], "objects should be serialized"
|
375
|
+
assert_kind_of Hash, hash[:sub_hash], "subhashes should be kept"
|
376
|
+
assert_equal object.to_s, hash[:sub_hash][:sub_object], "subhash members should be serialized"
|
377
|
+
assert_kind_of Array, hash[:array], "arrays should be kept"
|
378
|
+
assert_equal object.to_s, hash[:array].first, "array members should be serialized"
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def assert_filters_hash(attribute)
|
383
|
+
filters = ["abc", :def]
|
384
|
+
original = { 'abc' => "123", 'def' => "456", 'ghi' => "789", 'nested' => { 'abc' => '100' },
|
385
|
+
'something_with_abc' => 'match the entire string'}
|
386
|
+
filtered = { 'abc' => "[FILTERED]",
|
387
|
+
'def' => "[FILTERED]",
|
388
|
+
'something_with_abc' => "match the entire string",
|
389
|
+
'ghi' => "789",
|
390
|
+
'nested' => { 'abc' => '[FILTERED]' } }
|
391
|
+
|
392
|
+
notice = build_notice(:params_filters => filters, attribute => original)
|
393
|
+
|
394
|
+
assert_equal(filtered,
|
395
|
+
notice.send(attribute))
|
396
|
+
end
|
397
|
+
|
398
|
+
def build_backtrace_array
|
399
|
+
["app/models/user.rb:13:in `magic'",
|
400
|
+
"app/controllers/users_controller.rb:8:in `index'"]
|
401
|
+
end
|
402
|
+
|
403
|
+
def hostname
|
404
|
+
`hostname`.chomp
|
405
|
+
end
|
406
|
+
end
|