jordan-brough-hoptoad_notifier 2.3.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.
Files changed (45) hide show
  1. data/CHANGELOG +161 -0
  2. data/INSTALL +25 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +384 -0
  5. data/Rakefile +217 -0
  6. data/SUPPORTED_RAILS_VERSIONS +9 -0
  7. data/TESTING.rdoc +8 -0
  8. data/generators/hoptoad/hoptoad_generator.rb +63 -0
  9. data/generators/hoptoad/lib/insert_commands.rb +34 -0
  10. data/generators/hoptoad/lib/rake_commands.rb +24 -0
  11. data/generators/hoptoad/templates/capistrano_hook.rb +6 -0
  12. data/generators/hoptoad/templates/hoptoad_notifier_tasks.rake +25 -0
  13. data/generators/hoptoad/templates/initializer.rb +6 -0
  14. data/lib/hoptoad_notifier.rb +148 -0
  15. data/lib/hoptoad_notifier/backtrace.rb +99 -0
  16. data/lib/hoptoad_notifier/capistrano.rb +20 -0
  17. data/lib/hoptoad_notifier/configuration.rb +232 -0
  18. data/lib/hoptoad_notifier/notice.rb +318 -0
  19. data/lib/hoptoad_notifier/rack.rb +40 -0
  20. data/lib/hoptoad_notifier/rails.rb +37 -0
  21. data/lib/hoptoad_notifier/rails/action_controller_catcher.rb +29 -0
  22. data/lib/hoptoad_notifier/rails/controller_methods.rb +63 -0
  23. data/lib/hoptoad_notifier/rails/error_lookup.rb +33 -0
  24. data/lib/hoptoad_notifier/rails3_tasks.rb +90 -0
  25. data/lib/hoptoad_notifier/railtie.rb +23 -0
  26. data/lib/hoptoad_notifier/sender.rb +63 -0
  27. data/lib/hoptoad_notifier/tasks.rb +97 -0
  28. data/lib/hoptoad_notifier/version.rb +3 -0
  29. data/lib/hoptoad_tasks.rb +44 -0
  30. data/lib/rails/generators/hoptoad/hoptoad_generator.rb +69 -0
  31. data/lib/templates/rescue.erb +91 -0
  32. data/rails/init.rb +1 -0
  33. data/script/integration_test.rb +38 -0
  34. data/test/backtrace_test.rb +118 -0
  35. data/test/catcher_test.rb +324 -0
  36. data/test/configuration_test.rb +208 -0
  37. data/test/helper.rb +239 -0
  38. data/test/hoptoad_tasks_test.rb +152 -0
  39. data/test/logger_test.rb +85 -0
  40. data/test/notice_test.rb +443 -0
  41. data/test/notifier_test.rb +222 -0
  42. data/test/rack_test.rb +58 -0
  43. data/test/rails_initializer_test.rb +36 -0
  44. data/test/sender_test.rb +123 -0
  45. metadata +205 -0
@@ -0,0 +1,208 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ConfigurationTest < Test::Unit::TestCase
4
+
5
+ include DefinesConstants
6
+
7
+ should "provide default values" do
8
+ assert_config_default :proxy_host, nil
9
+ assert_config_default :proxy_port, nil
10
+ assert_config_default :proxy_user, nil
11
+ assert_config_default :proxy_pass, nil
12
+ assert_config_default :project_root, nil
13
+ assert_config_default :environment_name, nil
14
+ assert_config_default :logger, nil
15
+ assert_config_default :notifier_version, HoptoadNotifier::VERSION
16
+ assert_config_default :notifier_name, 'Hoptoad Notifier'
17
+ assert_config_default :notifier_url, 'http://hoptoadapp.com'
18
+ assert_config_default :secure, false
19
+ assert_config_default :host, 'hoptoadapp.com'
20
+ assert_config_default :http_open_timeout, 2
21
+ assert_config_default :http_read_timeout, 5
22
+ assert_config_default :ignore_by_filters, []
23
+ assert_config_default :ignore_user_agent, []
24
+ assert_config_default :params_filters,
25
+ HoptoadNotifier::Configuration::DEFAULT_PARAMS_FILTERS
26
+ assert_config_default :backtrace_filters,
27
+ HoptoadNotifier::Configuration::DEFAULT_BACKTRACE_FILTERS
28
+ assert_config_default :ignore,
29
+ HoptoadNotifier::Configuration::IGNORE_DEFAULT
30
+ assert_config_default :development_lookup, true
31
+ assert_config_default :framework, 'Standalone'
32
+ end
33
+
34
+ should "provide default values for secure connections" do
35
+ config = HoptoadNotifier::Configuration.new
36
+ config.secure = true
37
+ assert_equal 443, config.port
38
+ assert_equal 'https', config.protocol
39
+ end
40
+
41
+ should "provide default values for insecure connections" do
42
+ config = HoptoadNotifier::Configuration.new
43
+ config.secure = false
44
+ assert_equal 80, config.port
45
+ assert_equal 'http', config.protocol
46
+ end
47
+
48
+ should "not cache inferred ports" do
49
+ config = HoptoadNotifier::Configuration.new
50
+ config.secure = false
51
+ config.port
52
+ config.secure = true
53
+ assert_equal 443, config.port
54
+ end
55
+
56
+ should "allow values to be overwritten" do
57
+ assert_config_overridable :proxy_host
58
+ assert_config_overridable :proxy_port
59
+ assert_config_overridable :proxy_user
60
+ assert_config_overridable :proxy_pass
61
+ assert_config_overridable :secure
62
+ assert_config_overridable :host
63
+ assert_config_overridable :port
64
+ assert_config_overridable :http_open_timeout
65
+ assert_config_overridable :http_read_timeout
66
+ assert_config_overridable :project_root
67
+ assert_config_overridable :notifier_version
68
+ assert_config_overridable :notifier_name
69
+ assert_config_overridable :notifier_url
70
+ assert_config_overridable :environment_name
71
+ assert_config_overridable :development_lookup
72
+ assert_config_overridable :logger
73
+ end
74
+
75
+ should "have an api key" do
76
+ assert_config_overridable :api_key
77
+ end
78
+
79
+ should "act like a hash" do
80
+ config = HoptoadNotifier::Configuration.new
81
+ hash = config.to_hash
82
+ [:api_key, :backtrace_filters, :development_environments,
83
+ :environment_name, :host, :http_open_timeout,
84
+ :http_read_timeout, :ignore, :ignore_by_filters, :ignore_user_agent,
85
+ :notifier_name, :notifier_url, :notifier_version, :params_filters,
86
+ :project_root, :port, :protocol, :proxy_host, :proxy_pass, :proxy_port,
87
+ :proxy_user, :secure, :development_lookup].each do |option|
88
+ assert_equal config[option], hash[option], "Wrong value for #{option}"
89
+ end
90
+ end
91
+
92
+ should "be mergable" do
93
+ config = HoptoadNotifier::Configuration.new
94
+ hash = config.to_hash
95
+ assert_equal hash.merge(:key => 'value'), config.merge(:key => 'value')
96
+ end
97
+
98
+ should "allow param filters to be appended" do
99
+ assert_appends_value :params_filters
100
+ end
101
+
102
+ should "warn when attempting to read environment filters" do
103
+ config = HoptoadNotifier::Configuration.new
104
+ config.
105
+ expects(:warn).
106
+ with(regexp_matches(/deprecated/i))
107
+ assert_equal [], config.environment_filters
108
+ end
109
+
110
+ should "allow ignored user agents to be appended" do
111
+ assert_appends_value :ignore_user_agent
112
+ end
113
+
114
+ should "allow backtrace filters to be appended" do
115
+ assert_appends_value(:backtrace_filters) do |config|
116
+ new_filter = lambda {}
117
+ config.filter_backtrace(&new_filter)
118
+ new_filter
119
+ end
120
+ end
121
+
122
+ should "allow ignore by filters to be appended" do
123
+ assert_appends_value(:ignore_by_filters) do |config|
124
+ new_filter = lambda {}
125
+ config.ignore_by_filter(&new_filter)
126
+ new_filter
127
+ end
128
+ end
129
+
130
+ should "allow ignored exceptions to be appended" do
131
+ config = HoptoadNotifier::Configuration.new
132
+ original_filters = config.ignore.dup
133
+ new_filter = 'hello'
134
+ config.ignore << new_filter
135
+ assert_same_elements original_filters + [new_filter], config.ignore
136
+ end
137
+
138
+ should "allow ignored exceptions to be replaced" do
139
+ assert_replaces(:ignore, :ignore_only=)
140
+ end
141
+
142
+ should "allow ignored user agents to be replaced" do
143
+ assert_replaces(:ignore_user_agent, :ignore_user_agent_only=)
144
+ end
145
+
146
+ should "use development and test as development environments by default" do
147
+ config = HoptoadNotifier::Configuration.new
148
+ assert_same_elements %w(development test cucumber), config.development_environments
149
+ end
150
+
151
+ should "be public in a public environment" do
152
+ config = HoptoadNotifier::Configuration.new
153
+ config.development_environments = %w(development)
154
+ config.environment_name = 'production'
155
+ assert config.public?
156
+ end
157
+
158
+ should "not be public in a development environment" do
159
+ config = HoptoadNotifier::Configuration.new
160
+ config.development_environments = %w(staging)
161
+ config.environment_name = 'staging'
162
+ assert !config.public?
163
+ end
164
+
165
+ should "be public without an environment name" do
166
+ config = HoptoadNotifier::Configuration.new
167
+ assert config.public?
168
+ end
169
+
170
+ should "use the assigned logger if set" do
171
+ config = HoptoadNotifier::Configuration.new
172
+ config.logger = "CUSTOM LOGGER"
173
+ assert_equal "CUSTOM LOGGER", config.logger
174
+ end
175
+
176
+ def assert_config_default(option, default_value, config = nil)
177
+ config ||= HoptoadNotifier::Configuration.new
178
+ assert_equal default_value, config.send(option)
179
+ end
180
+
181
+ def assert_config_overridable(option, value = 'a value')
182
+ config = HoptoadNotifier::Configuration.new
183
+ config.send(:"#{option}=", value)
184
+ assert_equal value, config.send(option)
185
+ end
186
+
187
+ def assert_appends_value(option, &block)
188
+ config = HoptoadNotifier::Configuration.new
189
+ original_values = config.send(option).dup
190
+ block ||= lambda do |config|
191
+ new_value = 'hello'
192
+ config.send(option) << new_value
193
+ new_value
194
+ end
195
+ new_value = block.call(config)
196
+ assert_same_elements original_values + [new_value], config.send(option)
197
+ end
198
+
199
+ def assert_replaces(option, setter)
200
+ config = HoptoadNotifier::Configuration.new
201
+ new_value = 'hello'
202
+ config.send(setter, [new_value])
203
+ assert_equal [new_value], config.send(option)
204
+ config.send(setter, new_value)
205
+ assert_equal [new_value], config.send(option)
206
+ end
207
+
208
+ end
@@ -0,0 +1,239 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+
4
+ gem 'jferris-mocha', '>= 0.9.5.0.1241126838'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), *%w[.. vendor ginger lib])
7
+ $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
8
+
9
+ require 'shoulda'
10
+ require 'mocha'
11
+
12
+ require 'ginger'
13
+
14
+ require 'action_controller'
15
+ require 'action_controller/test_process'
16
+ require 'active_record'
17
+ require 'active_record/base'
18
+ require 'active_support'
19
+ require 'nokogiri'
20
+ require 'rack'
21
+
22
+ require "hoptoad_notifier"
23
+
24
+ begin require 'redgreen'; rescue LoadError; end
25
+
26
+ module TestMethods
27
+ def rescue_action e
28
+ raise e
29
+ end
30
+
31
+ def do_raise
32
+ raise "Hoptoad"
33
+ end
34
+
35
+ def do_not_raise
36
+ render :text => "Success"
37
+ end
38
+
39
+ def do_raise_ignored
40
+ raise ActiveRecord::RecordNotFound.new("404")
41
+ end
42
+
43
+ def do_raise_not_ignored
44
+ raise ActiveRecord::StatementInvalid.new("Statement invalid")
45
+ end
46
+
47
+ def manual_notify
48
+ notify_hoptoad(Exception.new)
49
+ render :text => "Success"
50
+ end
51
+
52
+ def manual_notify_ignored
53
+ notify_hoptoad(ActiveRecord::RecordNotFound.new("404"))
54
+ render :text => "Success"
55
+ end
56
+ end
57
+
58
+ class HoptoadController < ActionController::Base
59
+ include TestMethods
60
+ end
61
+
62
+ class Test::Unit::TestCase
63
+ def request(action = nil, method = :get, user_agent = nil, params = {})
64
+ @request = ActionController::TestRequest.new
65
+ @request.action = action ? action.to_s : ""
66
+
67
+ if user_agent
68
+ if @request.respond_to?(:user_agent=)
69
+ @request.user_agent = user_agent
70
+ else
71
+ @request.env["HTTP_USER_AGENT"] = user_agent
72
+ end
73
+ end
74
+ @request.query_parameters = @request.query_parameters.merge(params)
75
+ @response = ActionController::TestResponse.new
76
+ @controller.process(@request, @response)
77
+ end
78
+
79
+ # Borrowed from ActiveSupport 2.3.2
80
+ def assert_difference(expression, difference = 1, message = nil, &block)
81
+ b = block.send(:binding)
82
+ exps = Array.wrap(expression)
83
+ before = exps.map { |e| eval(e, b) }
84
+
85
+ yield
86
+
87
+ exps.each_with_index do |e, i|
88
+ error = "#{e.inspect} didn't change by #{difference}"
89
+ error = "#{message}.\n#{error}" if message
90
+ assert_equal(before[i] + difference, eval(e, b), error)
91
+ end
92
+ end
93
+
94
+ def assert_no_difference(expression, message = nil, &block)
95
+ assert_difference expression, 0, message, &block
96
+ end
97
+
98
+ def stub_sender
99
+ stub('sender', :send_to_hoptoad => nil)
100
+ end
101
+
102
+ def stub_sender!
103
+ HoptoadNotifier.sender = stub_sender
104
+ end
105
+
106
+ def stub_notice
107
+ stub('notice', :to_xml => 'some yaml', :ignore? => false)
108
+ end
109
+
110
+ def stub_notice!
111
+ returning stub_notice do |notice|
112
+ HoptoadNotifier::Notice.stubs(:new => notice)
113
+ end
114
+ end
115
+
116
+ def create_dummy
117
+ HoptoadNotifier::DummySender.new
118
+ end
119
+
120
+ def reset_config
121
+ HoptoadNotifier.configuration = nil
122
+ HoptoadNotifier.configure do |config|
123
+ config.api_key = 'abc123'
124
+ end
125
+ end
126
+
127
+ def clear_backtrace_filters
128
+ HoptoadNotifier.configuration.backtrace_filters.clear
129
+ end
130
+
131
+ def build_exception
132
+ raise
133
+ rescue => caught_exception
134
+ caught_exception
135
+ end
136
+
137
+ def build_notice_data(exception = nil)
138
+ exception ||= build_exception
139
+ {
140
+ :api_key => 'abc123',
141
+ :error_class => exception.class.name,
142
+ :error_message => "#{exception.class.name}: #{exception.message}",
143
+ :backtrace => exception.backtrace,
144
+ :environment => { 'PATH' => '/bin', 'REQUEST_URI' => '/users/1' },
145
+ :request => {
146
+ :params => { 'controller' => 'users', 'action' => 'show', 'id' => '1' },
147
+ :rails_root => '/path/to/application',
148
+ :url => "http://test.host/users/1"
149
+ },
150
+ :session => {
151
+ :key => '123abc',
152
+ :data => { 'user_id' => '5', 'flash' => { 'notice' => 'Logged in successfully' } }
153
+ }
154
+ }
155
+ end
156
+
157
+ def assert_caught_and_sent
158
+ assert !HoptoadNotifier.sender.collected.empty?
159
+ end
160
+
161
+ def assert_caught_and_not_sent
162
+ assert HoptoadNotifier.sender.collected.empty?
163
+ end
164
+
165
+ def assert_array_starts_with(expected, actual)
166
+ assert_respond_to actual, :to_ary
167
+ array = actual.to_ary.reverse
168
+ expected.reverse.each_with_index do |value, i|
169
+ assert_equal value, array[i]
170
+ end
171
+ end
172
+
173
+ def assert_valid_node(document, xpath, content)
174
+ nodes = document.xpath(xpath)
175
+ assert nodes.any?{|node| node.content == content },
176
+ "Expected xpath #{xpath} to have content #{content}, " +
177
+ "but found #{nodes.map { |n| n.content }} in #{nodes.size} matching nodes." +
178
+ "Document:\n#{document.to_s}"
179
+ end
180
+ end
181
+
182
+ module DefinesConstants
183
+ def setup
184
+ @defined_constants = []
185
+ end
186
+
187
+ def teardown
188
+ @defined_constants.each do |constant|
189
+ Object.__send__(:remove_const, constant)
190
+ end
191
+ end
192
+
193
+ def define_constant(name, value)
194
+ Object.const_set(name, value)
195
+ @defined_constants << name
196
+ end
197
+ end
198
+
199
+ # Also stolen from AS 2.3.2
200
+ class Array
201
+ # Wraps the object in an Array unless it's an Array. Converts the
202
+ # object to an Array using #to_ary if it implements that.
203
+ def self.wrap(object)
204
+ case object
205
+ when nil
206
+ []
207
+ when self
208
+ object
209
+ else
210
+ if object.respond_to?(:to_ary)
211
+ object.to_ary
212
+ else
213
+ [object]
214
+ end
215
+ end
216
+ end
217
+
218
+ end
219
+
220
+ class CollectingSender
221
+ attr_reader :collected
222
+
223
+ def initialize
224
+ @collected = []
225
+ end
226
+
227
+ def send_to_hoptoad(data)
228
+ @collected << data
229
+ end
230
+ end
231
+
232
+ class FakeLogger
233
+ def info(*args); end
234
+ def debug(*args); end
235
+ def warn(*args); end
236
+ def error(*args); end
237
+ def fatal(*args); end
238
+ end
239
+
@@ -0,0 +1,152 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'rubygems'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/hoptoad_tasks'
5
+ require 'fakeweb'
6
+
7
+ FakeWeb.allow_net_connect = false
8
+
9
+ class HoptoadTasksTest < Test::Unit::TestCase
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 { HoptoadTasks.stubs(:puts) }
24
+
25
+ context "in a configured project" do
26
+ setup { HoptoadNotifier.configure { |config| config.api_key = "1234123412341234" } }
27
+
28
+ context "on deploy({})" do
29
+ setup { @output = HoptoadTasks.deploy({}) }
30
+
31
+ before_should "complain about missing rails env" do
32
+ HoptoadTasks.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", :post_form => @response)
44
+
45
+ Net::HTTP.expects(:Proxy).
46
+ with(HoptoadNotifier.configuration.proxy_host,
47
+ HoptoadNotifier.configuration.proxy_port,
48
+ HoptoadNotifier.configuration.proxy_user,
49
+ HoptoadNotifier.configuration.proxy_pass).
50
+ returns(@http_proxy)
51
+
52
+ @options = { :rails_env => "staging" }
53
+ end
54
+
55
+ context "on deploy(options)" do
56
+ setup do
57
+ @output = HoptoadTasks.deploy(@options)
58
+ end
59
+
60
+ before_should "post to http://hoptoadapp.com/deploys.txt" do
61
+ URI.stubs(:parse).with('http://hoptoadapp.com/deploys.txt').returns(:uri)
62
+ @http_proxy.expects(:post_form).with(:uri, kind_of(Hash)).returns(successful_response)
63
+ end
64
+
65
+ before_should "use the project api key" do
66
+ @http_proxy.expects(:post_form).
67
+ with(kind_of(URI), has_entries('api_key' => "1234123412341234")).
68
+ returns(successful_response)
69
+ end
70
+
71
+ before_should "use send the rails_env param" do
72
+ @http_proxy.expects(:post_form).
73
+ with(kind_of(URI), has_entries("deploy[rails_env]" => "staging")).
74
+ returns(successful_response)
75
+ end
76
+
77
+ [:local_username, :scm_repository, :scm_revision].each do |key|
78
+ before_should "use send the #{key} param if it's passed in." do
79
+ @options[key] = "value"
80
+ @http_proxy.expects(:post_form).
81
+ with(kind_of(URI), has_entries("deploy[#{key}]" => "value")).
82
+ returns(successful_response)
83
+ end
84
+ end
85
+
86
+ before_should "use the :api_key param if it's passed in." do
87
+ @options[:api_key] = "value"
88
+ @http_proxy.expects(:post_form).
89
+ with(kind_of(URI), has_entries("api_key" => "value")).
90
+ returns(successful_response)
91
+ end
92
+
93
+ before_should "puts the response body on success" do
94
+ HoptoadTasks.expects(:puts).with("body")
95
+ @http_proxy.expects(:post_form).with(any_parameters).returns(successful_response('body'))
96
+ end
97
+
98
+ before_should "puts the response body on failure" do
99
+ HoptoadTasks.expects(:puts).with("body")
100
+ @http_proxy.expects(:post_form).with(any_parameters).returns(unsuccessful_response('body'))
101
+ end
102
+
103
+ should "return false on failure", :before => lambda {
104
+ @http_proxy.expects(:post_form).with(any_parameters).returns(unsuccessful_response('body'))
105
+ } do
106
+ assert !@output
107
+ end
108
+
109
+ should "return true on success", :before => lambda {
110
+ @http_proxy.expects(:post_form).with(any_parameters).returns(successful_response('body'))
111
+ } do
112
+ assert @output
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ context "in a configured project with custom host" do
119
+ setup do
120
+ HoptoadNotifier.configure do |config|
121
+ config.api_key = "1234123412341234"
122
+ config.host = "custom.host"
123
+ end
124
+ end
125
+
126
+ context "on deploy(:rails_env => 'staging')" do
127
+ setup { @output = HoptoadTasks.deploy(:rails_env => "staging") }
128
+
129
+ before_should "post to the custom host" do
130
+ URI.stubs(:parse).with('http://custom.host/deploys.txt').returns(:uri)
131
+ Net::HTTP.expects(:post_form).with(:uri, kind_of(Hash)).returns(successful_response)
132
+ end
133
+ end
134
+ end
135
+
136
+ context "when not configured" do
137
+ setup { HoptoadNotifier.configure { |config| config.api_key = "" } }
138
+
139
+ context "on deploy(:rails_env => 'staging')" do
140
+ setup { @output = HoptoadTasks.deploy(:rails_env => "staging") }
141
+
142
+ before_should "complain about missing api key" do
143
+ HoptoadTasks.expects(:puts).with(regexp_matches(/api key/i))
144
+ end
145
+
146
+ should "return false" do
147
+ assert !@output
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end