honeybadger 1.16.7 → 2.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +19 -0
  3. data/README.md +37 -16
  4. data/bin/honeybadger +5 -0
  5. data/lib/honeybadger.rb +167 -191
  6. data/lib/honeybadger/agent.rb +136 -0
  7. data/lib/honeybadger/backend.rb +26 -0
  8. data/lib/honeybadger/backend/base.rb +66 -0
  9. data/lib/honeybadger/backend/debug.rb +12 -0
  10. data/lib/honeybadger/backend/null.rb +16 -0
  11. data/lib/honeybadger/backend/server.rb +51 -0
  12. data/lib/honeybadger/backend/test.rb +24 -0
  13. data/lib/honeybadger/backtrace.rb +29 -24
  14. data/lib/honeybadger/cli.rb +367 -0
  15. data/lib/honeybadger/config.rb +333 -0
  16. data/lib/honeybadger/config/callbacks.rb +70 -0
  17. data/lib/honeybadger/config/defaults.rb +175 -0
  18. data/lib/honeybadger/config/env.rb +40 -0
  19. data/lib/honeybadger/config/yaml.rb +43 -0
  20. data/lib/honeybadger/const.rb +28 -0
  21. data/lib/honeybadger/init/rails.rb +84 -0
  22. data/lib/honeybadger/init/sinatra.rb +27 -0
  23. data/lib/honeybadger/logging.rb +133 -0
  24. data/lib/honeybadger/notice.rb +243 -280
  25. data/lib/honeybadger/plugin.rb +110 -0
  26. data/lib/honeybadger/plugins/delayed_job.rb +22 -0
  27. data/lib/honeybadger/{integrations → plugins}/delayed_job/plugin.rb +6 -7
  28. data/lib/honeybadger/{integrations → plugins}/local_variables.rb +7 -8
  29. data/lib/honeybadger/{integrations → plugins}/net_http.rb +10 -8
  30. data/lib/honeybadger/plugins/passenger.rb +24 -0
  31. data/lib/honeybadger/plugins/rails.rb +61 -0
  32. data/lib/honeybadger/plugins/sidekiq.rb +35 -0
  33. data/lib/honeybadger/{integrations → plugins}/thor.rb +9 -8
  34. data/lib/honeybadger/{integrations → plugins}/unicorn.rb +10 -9
  35. data/lib/honeybadger/rack/error_notifier.rb +44 -27
  36. data/lib/honeybadger/rack/metrics_reporter.rb +41 -0
  37. data/lib/honeybadger/rack/request_hash.rb +50 -0
  38. data/lib/honeybadger/rack/user_feedback.rb +15 -10
  39. data/lib/honeybadger/rack/user_informer.rb +14 -3
  40. data/lib/honeybadger/trace.rb +185 -0
  41. data/lib/honeybadger/util/http.rb +79 -0
  42. data/lib/honeybadger/util/request_sanitizer.rb +35 -0
  43. data/lib/honeybadger/util/sanitizer.rb +71 -0
  44. data/lib/honeybadger/util/stats.rb +31 -0
  45. data/lib/honeybadger/version.rb +4 -0
  46. data/lib/honeybadger/worker.rb +224 -0
  47. data/lib/honeybadger/worker/batch.rb +50 -0
  48. data/lib/honeybadger/worker/metered_queue.rb +80 -0
  49. data/lib/honeybadger/worker/metrics_collection.rb +61 -0
  50. data/lib/honeybadger/worker/metrics_collector.rb +96 -0
  51. data/{lib/honeybadger/capistrano.rb → vendor/capistrano-honeybadger/lib/capistrano/honeybadger.rb} +1 -3
  52. data/vendor/capistrano-honeybadger/lib/capistrano/tasks/deploy.cap +76 -0
  53. data/vendor/capistrano-honeybadger/lib/honeybadger/capistrano.rb +2 -0
  54. data/{lib → vendor/capistrano-honeybadger/lib}/honeybadger/capistrano/legacy.rb +16 -15
  55. data/vendor/thor/lib/thor.rb +484 -0
  56. data/vendor/thor/lib/thor/actions.rb +319 -0
  57. data/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  58. data/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  59. data/vendor/thor/lib/thor/actions/directory.rb +118 -0
  60. data/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  61. data/vendor/thor/lib/thor/actions/file_manipulation.rb +316 -0
  62. data/vendor/thor/lib/thor/actions/inject_into_file.rb +107 -0
  63. data/vendor/thor/lib/thor/base.rb +656 -0
  64. data/vendor/thor/lib/thor/command.rb +133 -0
  65. data/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +77 -0
  66. data/vendor/thor/lib/thor/core_ext/io_binary_read.rb +10 -0
  67. data/vendor/thor/lib/thor/core_ext/ordered_hash.rb +98 -0
  68. data/vendor/thor/lib/thor/error.rb +32 -0
  69. data/vendor/thor/lib/thor/group.rb +281 -0
  70. data/vendor/thor/lib/thor/invocation.rb +178 -0
  71. data/vendor/thor/lib/thor/line_editor.rb +17 -0
  72. data/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  73. data/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  74. data/vendor/thor/lib/thor/parser.rb +4 -0
  75. data/vendor/thor/lib/thor/parser/argument.rb +73 -0
  76. data/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  77. data/vendor/thor/lib/thor/parser/option.rb +125 -0
  78. data/vendor/thor/lib/thor/parser/options.rb +218 -0
  79. data/vendor/thor/lib/thor/rake_compat.rb +71 -0
  80. data/vendor/thor/lib/thor/runner.rb +322 -0
  81. data/vendor/thor/lib/thor/shell.rb +81 -0
  82. data/vendor/thor/lib/thor/shell/basic.rb +421 -0
  83. data/vendor/thor/lib/thor/shell/color.rb +149 -0
  84. data/vendor/thor/lib/thor/shell/html.rb +126 -0
  85. data/vendor/thor/lib/thor/util.rb +267 -0
  86. data/vendor/thor/lib/thor/version.rb +3 -0
  87. metadata +97 -305
  88. data/Appraisals +0 -95
  89. data/CHANGELOG.md +0 -422
  90. data/Gemfile +0 -8
  91. data/Gemfile.lock +0 -136
  92. data/Guardfile +0 -5
  93. data/MIT-LICENSE +0 -32
  94. data/Rakefile +0 -159
  95. data/features/metal.feature +0 -20
  96. data/features/rack.feature +0 -55
  97. data/features/rails.feature +0 -343
  98. data/features/rails3.x.feature +0 -26
  99. data/features/rake.feature +0 -25
  100. data/features/sinatra.feature +0 -27
  101. data/features/standalone.feature +0 -73
  102. data/features/step_definitions/metal_steps.rb +0 -24
  103. data/features/step_definitions/rack_steps.rb +0 -18
  104. data/features/step_definitions/rails_steps.rb +0 -270
  105. data/features/step_definitions/rake_steps.rb +0 -17
  106. data/features/step_definitions/standalone_steps.rb +0 -12
  107. data/features/step_definitions/thor_steps.rb +0 -4
  108. data/features/support/env.rb +0 -22
  109. data/features/support/honeybadger_failure_shim.rb.template +0 -5
  110. data/features/support/honeybadger_shim.rb.template +0 -6
  111. data/features/support/rails.rb +0 -202
  112. data/features/support/rake/Rakefile +0 -68
  113. data/features/support/test.thor +0 -22
  114. data/features/thor.feature +0 -5
  115. data/gemfiles/binding_of_caller.gemfile +0 -13
  116. data/gemfiles/delayed_job.gemfile +0 -13
  117. data/gemfiles/rack.gemfile +0 -13
  118. data/gemfiles/rails.gemfile +0 -16
  119. data/gemfiles/rails2.3.gemfile +0 -15
  120. data/gemfiles/rails3.0.gemfile +0 -16
  121. data/gemfiles/rails3.1.gemfile +0 -16
  122. data/gemfiles/rails3.2.gemfile +0 -16
  123. data/gemfiles/rails4.0.gemfile +0 -16
  124. data/gemfiles/rails4.1.gemfile +0 -16
  125. data/gemfiles/rake.gemfile +0 -13
  126. data/gemfiles/sinatra.gemfile +0 -13
  127. data/gemfiles/standalone.gemfile +0 -12
  128. data/gemfiles/thor.gemfile +0 -13
  129. data/generators/honeybadger/honeybadger_generator.rb +0 -95
  130. data/generators/honeybadger/lib/insert_commands.rb +0 -34
  131. data/generators/honeybadger/lib/rake_commands.rb +0 -24
  132. data/generators/honeybadger/templates/capistrano_hook.rb +0 -6
  133. data/generators/honeybadger/templates/honeybadger_tasks.rake +0 -25
  134. data/generators/honeybadger/templates/initializer.rb +0 -6
  135. data/honeybadger.gemspec +0 -174
  136. data/lib/honeybadger/array.rb +0 -53
  137. data/lib/honeybadger/capistrano/tasks.rake +0 -73
  138. data/lib/honeybadger/configuration.rb +0 -397
  139. data/lib/honeybadger/dependency.rb +0 -65
  140. data/lib/honeybadger/integrations.rb +0 -9
  141. data/lib/honeybadger/integrations/delayed_job.rb +0 -20
  142. data/lib/honeybadger/integrations/passenger.rb +0 -18
  143. data/lib/honeybadger/integrations/sidekiq.rb +0 -37
  144. data/lib/honeybadger/monitor.rb +0 -17
  145. data/lib/honeybadger/monitor/railtie.rb +0 -53
  146. data/lib/honeybadger/monitor/sender.rb +0 -44
  147. data/lib/honeybadger/monitor/trace.rb +0 -187
  148. data/lib/honeybadger/monitor/worker.rb +0 -169
  149. data/lib/honeybadger/payload.rb +0 -101
  150. data/lib/honeybadger/rack.rb +0 -12
  151. data/lib/honeybadger/rails.rb +0 -45
  152. data/lib/honeybadger/rails/action_controller_catcher.rb +0 -30
  153. data/lib/honeybadger/rails/controller_methods.rb +0 -78
  154. data/lib/honeybadger/rails/middleware/exceptions_catcher.rb +0 -29
  155. data/lib/honeybadger/rails3_tasks.rb +0 -94
  156. data/lib/honeybadger/railtie.rb +0 -52
  157. data/lib/honeybadger/rake_handler.rb +0 -66
  158. data/lib/honeybadger/sender.rb +0 -185
  159. data/lib/honeybadger/shared_tasks.rb +0 -56
  160. data/lib/honeybadger/stats.rb +0 -29
  161. data/lib/honeybadger/tasks.rb +0 -95
  162. data/lib/honeybadger/user_feedback.rb +0 -8
  163. data/lib/honeybadger/user_informer.rb +0 -8
  164. data/lib/honeybadger_tasks.rb +0 -69
  165. data/lib/rails/generators/honeybadger/honeybadger_generator.rb +0 -99
  166. data/rails/init.rb +0 -1
  167. data/resources/README.md +0 -34
  168. data/script/integration_test.rb +0 -38
  169. data/spec/allocation_stats.rb +0 -32
  170. data/spec/honeybadger/backtrace_spec.rb +0 -242
  171. data/spec/honeybadger/capistrano_spec.rb +0 -36
  172. data/spec/honeybadger/configuration_spec.rb +0 -328
  173. data/spec/honeybadger/dependency_spec.rb +0 -134
  174. data/spec/honeybadger/integrations/delayed_job_spec.rb +0 -82
  175. data/spec/honeybadger/integrations/local_variables_spec.rb +0 -60
  176. data/spec/honeybadger/integrations/net_http_spec.rb +0 -29
  177. data/spec/honeybadger/integrations/passenger_spec.rb +0 -29
  178. data/spec/honeybadger/integrations/sidekiq_spec.rb +0 -60
  179. data/spec/honeybadger/integrations/thor_spec.rb +0 -32
  180. data/spec/honeybadger/integrations/unicorn_spec.rb +0 -40
  181. data/spec/honeybadger/logger_spec.rb +0 -79
  182. data/spec/honeybadger/monitor/trace_spec.rb +0 -65
  183. data/spec/honeybadger/monitor/worker_spec.rb +0 -274
  184. data/spec/honeybadger/notice_spec.rb +0 -669
  185. data/spec/honeybadger/notifier_spec.rb +0 -328
  186. data/spec/honeybadger/payload_spec.rb +0 -162
  187. data/spec/honeybadger/rack_spec.rb +0 -85
  188. data/spec/honeybadger/rails/action_controller_spec.rb +0 -328
  189. data/spec/honeybadger/rails_spec.rb +0 -37
  190. data/spec/honeybadger/sender_spec.rb +0 -317
  191. data/spec/honeybadger/stats_spec.rb +0 -57
  192. data/spec/honeybadger/user_feedback_spec.rb +0 -80
  193. data/spec/honeybadger/user_informer_spec.rb +0 -30
  194. data/spec/honeybadger_tasks_spec.rb +0 -171
  195. data/spec/spec_helper.rb +0 -24
  196. data/spec/support/array_including.rb +0 -31
  197. data/spec/support/backtraced_exception.rb +0 -9
  198. data/spec/support/collected_sender.rb +0 -12
  199. data/spec/support/defines_constants.rb +0 -18
  200. data/spec/support/helpers.rb +0 -101
@@ -1,274 +0,0 @@
1
- require 'spec_helper'
2
- require 'honeybadger/monitor'
3
-
4
- describe Honeybadger::Monitor::Worker do
5
- let(:instance) { Honeybadger::Monitor::Worker.send(:new) }
6
- subject { instance }
7
-
8
- before(:each) do
9
- Thread.stub(:new)
10
-
11
- # Create attr_readers for testing values
12
- instance.stub(:metrics) { instance.instance_variable_get(:@metrics) }
13
- instance.stub(:traces) { instance.instance_variable_get(:@traces) }
14
- instance.stub(:sender) { instance.instance_variable_get(:@sender) }
15
- instance.stub(:thread) { instance.instance_variable_get(:@thread) }
16
- instance.stub(:lock) { instance.instance_variable_get(:@lock) }
17
- end
18
-
19
- describe "#queue_trace" do
20
- let(:trace) { Honeybadger::Monitor::Trace.new(:foo) }
21
-
22
- context "when a trace exists" do
23
- before do
24
- trace.stub(:key).and_return(:bar)
25
- subject.pending_traces[:foo] = trace
26
- Thread.current[:hb_trace_id] = :foo
27
- end
28
-
29
- context "and the same trace key exists" do
30
- let(:old_trace) { Honeybadger::Monitor::Trace.new(:foo) }
31
-
32
- before do
33
- old_trace.stub(:duration).and_return(2000)
34
- old_trace.stub(:key).and_return(:bar)
35
- subject.traces[:bar] = old_trace
36
- end
37
-
38
- context "and the new duration is not greater" do
39
- before { trace.stub(:duration).and_return(2000) }
40
-
41
- it "replaces the existing trace" do
42
- expect { subject.queue_trace }.not_to change { subject.traces[:bar] }.from(old_trace)
43
- end
44
- end
45
-
46
- context "and the new duration is greater" do
47
- before { trace.stub(:duration).and_return(3000) }
48
-
49
- it "replaces the existing trace" do
50
- expect { subject.queue_trace }.to change { subject.traces[:bar] }.from(old_trace).to(trace)
51
- end
52
- end
53
- end
54
- end
55
- end
56
-
57
- describe "#fork" do
58
- before { Thread.unstub(:new) }
59
- before { Honeybadger.stub(:write_verbose_log) }
60
- before { subject.start }
61
- after { subject.stop }
62
-
63
- it "logs debug information" do
64
- Honeybadger.should_receive(:write_verbose_log).with(/forking/i)
65
- subject.fork
66
- end
67
-
68
- it "restarts the worker thread" do
69
- old_thread = instance.thread
70
- subject.fork
71
- expect(instance.thread).not_to be old_thread
72
- end
73
-
74
- it "unlocks the mutex first" do
75
- instance.lock.lock
76
- expect { subject.fork }.not_to raise_error
77
- end
78
- end
79
-
80
- describe '#initialize' do
81
- describe '@metrics' do
82
- subject { instance.instance_variable_get(:@metrics) }
83
-
84
- it { should have_key(:timing) }
85
- it { should have_key(:counter) }
86
-
87
- it 'is initialized timing with empty hash' do
88
- expect(subject[:timing]).to eq({})
89
- end
90
-
91
- it 'is initialized counter with empty hash' do
92
- expect(subject[:counter]).to eq({})
93
- end
94
- end
95
-
96
- describe '@traces' do
97
- subject { instance.traces }
98
-
99
- it { should be_empty }
100
- end
101
-
102
- describe '@delay' do
103
- subject { instance.instance_variable_get(:@delay) }
104
- it { should eq 60 }
105
- end
106
-
107
- describe '@per_request' do
108
- subject { instance.instance_variable_get(:@per_request) }
109
- it { should eq 100 }
110
- end
111
-
112
- describe '@sender' do
113
- subject { instance.instance_variable_get(:@sender) }
114
-
115
- it { should be_a Honeybadger::Monitor::Sender }
116
- it { should be_a Honeybadger::Sender }
117
-
118
- it 'is initialized with Honeybadger configuration' do
119
- Honeybadger::Monitor::Sender.should_receive(:new).with(Honeybadger.configuration)
120
- Honeybadger::Monitor::Worker.send(:new)
121
- end
122
- end
123
-
124
- it 'starts the worker loop'
125
- end
126
-
127
- describe '#start' do
128
- it 'creates a new Thread'
129
- end
130
-
131
- describe '#stop' do
132
- it 'asks current thread to exit gracefully'
133
- end
134
-
135
- describe '#timing' do
136
- before(:each) do
137
- expect(instance.metrics[:timing]).to be_empty
138
- instance.timing(:test, 50)
139
- end
140
-
141
- it 'adds value to metrics hash' do
142
- expect(instance.metrics[:timing][:test]).to eq [50]
143
- end
144
-
145
- it 'appends to existing values' do
146
- instance.timing(:test, 60)
147
- expect(instance.metrics[:timing][:test]).to eq [50, 60]
148
- end
149
- end
150
-
151
- describe '#increment' do
152
- before(:each) do
153
- expect(instance.metrics[:counter]).to be_empty
154
- instance.increment(:test, 50)
155
- end
156
-
157
- it 'adds value to metrics hash' do
158
- expect(instance.metrics[:counter][:test]).to eq [50]
159
- end
160
-
161
- it 'appends to existing values' do
162
- instance.increment(:test, 60)
163
- expect(instance.metrics[:counter][:test]).to eq [50, 60]
164
- end
165
- end
166
-
167
- describe '#send_metrics' do
168
- subject { instance.send(:send_metrics) }
169
-
170
- it 're-inits metrics' do
171
- instance.increment(:test, 60)
172
- previous_metrics = instance.metrics
173
- expect { subject }.to change(instance, :metrics).to({ :timing => {}, :counter => {} })
174
- expect(instance.metrics).not_to be(previous_metrics)
175
- end
176
-
177
- it 'returns nil when there are no metrics to send' do
178
- expect(instance.metrics[:timing]).to be_empty
179
- expect(instance.metrics[:counter]).to be_empty
180
- instance.sender.should_not_receive(:send_metrics)
181
- expect(subject).to be_nil
182
- end
183
-
184
- it 'returns nil after sending metrics' do
185
- instance.increment(:test, 60)
186
- instance.should_not_receive(:log)
187
- instance.sender.should_receive(:send_metrics)
188
- expect(subject).to be_nil
189
- end
190
-
191
- context 'when constructing timing metrics' do
192
- before(:each) { 10.times { |i| instance.timing(:test, i) } }
193
-
194
- it 'includes the mean value' do
195
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test:mean 4.5'])))
196
- end
197
-
198
- it 'includes the median value' do
199
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test:median 5'])))
200
- end
201
-
202
- it 'includes the percentile_90 value' do
203
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test:percentile_90 9'])))
204
- end
205
-
206
- it 'includes the min value' do
207
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test:min 0'])))
208
- end
209
-
210
- it 'includes the max value' do
211
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test:max 9'])))
212
- end
213
-
214
- it 'includes the stddev value' do
215
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(/test:stddev 3.027/)))
216
- end
217
-
218
- it 'includes a count of total metrics' do
219
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including(['test 10'])))
220
- end
221
-
222
- after(:each) { subject }
223
- end
224
-
225
- context 'when constructing counter metrics' do
226
- it 'sums the values of each metric' do
227
- 10.times { instance.increment(:test, 1) }
228
- instance.sender.should_receive(:send_metrics).with(hash_including(:metrics => array_including('test 10')))
229
- subject
230
- end
231
- end
232
-
233
- context 'when sending metrics' do
234
- before(:each) { instance.increment(:test, 1) }
235
-
236
- it 'executes batches of 100' do
237
- 199.times { |i| instance.increment(:"test_#{i}", 1) }
238
- instance.sender.should_receive(:send_metrics).exactly(2).times
239
- end
240
-
241
- it 'includes the configured environment' do
242
- Honeybadger.configure do |c|
243
- c.environment_name = 'asdf'
244
- end
245
- instance.sender.should_receive(:send_metrics).with(hash_including(:environment => 'asdf'))
246
- end
247
-
248
- it 'includes the configured hostname' do
249
- Honeybadger.configure do |c|
250
- c.hostname = 'zxcv'
251
- end
252
- instance.sender.should_receive(:send_metrics).with(hash_including(:hostname => 'zxcv'))
253
- end
254
-
255
- after(:each) { subject }
256
- end
257
-
258
- context 'when an exception occurrs' do
259
- before(:each) do
260
- instance.increment(:test, 1)
261
- instance.sender.stub(:send_metrics).and_raise(RuntimeError.new('cobra attack!'))
262
- end
263
-
264
- it 'logs the exception' do
265
- instance.should_receive(:log).with(:error, /cobra attack/)
266
- expect { subject }.not_to raise_error
267
- end
268
-
269
- it 'returns nil' do
270
- expect(subject).to be_nil
271
- end
272
- end
273
- end
274
- end
@@ -1,669 +0,0 @@
1
- require 'spec_helper'
2
- require 'json'
3
- require 'rack'
4
-
5
- describe Honeybadger::Notice do
6
- def configure
7
- Honeybadger::Configuration.new.tap do |config|
8
- config.api_key = 'abc123def456'
9
- end
10
- end
11
-
12
- def build_notice(args = {})
13
- configuration = args.delete(:configuration) || configure
14
- Honeybadger::Notice.new(configuration.merge(args))
15
- end
16
-
17
- context '#deliver' do
18
- context 'sender is configured' do
19
- it "delivers to sender" do
20
- sender = stub_sender!
21
- notice = build_notice
22
- notice.stub(:to_json => { :foo => 'bar' })
23
-
24
- sender.should_receive(:send_to_honeybadger).with(notice)
25
- notice.deliver
26
- end
27
- end
28
-
29
- context 'sender is not configured' do
30
- it "returns false" do
31
- notice = build_notice
32
- Honeybadger.sender = nil
33
- expect(notice.deliver).to be_false
34
- end
35
- end
36
- end
37
-
38
- it "generates json from as_json template" do
39
- notice = build_notice
40
- hash = {'foo' => 'bar'}
41
- notice.should_receive(:as_json).once.and_return(hash)
42
- json = notice.to_json
43
-
44
- payload = nil
45
- expect { payload = JSON.parse(json) }.not_to raise_error
46
-
47
- expect(payload).to eq hash
48
- end
49
-
50
- it "accepts a project root" do
51
- project_root = '/path/to/project'
52
- notice = build_notice(:project_root => project_root)
53
- expect(notice.project_root).to eq project_root
54
- end
55
-
56
- it "accepts a component" do
57
- expect(build_notice(:component => 'users_controller').controller).to eq 'users_controller'
58
- end
59
-
60
- it "aliases the component as controller" do
61
- expect(build_notice(:controller => 'users_controller').component).to eq 'users_controller'
62
- expect(build_notice(:controller => 'users_controller').controller).to eq 'users_controller'
63
- end
64
-
65
- it "accepts a action" do
66
- expect(build_notice(:action => 'index').action).to eq 'index'
67
- end
68
-
69
- it "accepts source excerpt radius" do
70
- expect(build_notice(:source_extract_radius => 3).source_extract_radius).to eq 3
71
- end
72
-
73
- it "accepts a url" do
74
- url = 'http://some.host/uri'
75
- notice = build_notice(:url => url)
76
- expect(notice.url).to eq url
77
- end
78
-
79
- it "initializes default features" do
80
- notice = build_notice(:features => nil)
81
- expect(notice.features).to eq({})
82
- end
83
-
84
- it "accepts features" do
85
- features = {'foo' => 'bar'}
86
- notice = build_notice(:features => features)
87
- expect(notice.features).to eq features
88
- end
89
-
90
- it "sets the host name" do
91
- notice = build_notice
92
- expect(notice.hostname).to eq hostname
93
- end
94
-
95
- it "overrides the host name" do
96
- notice = build_notice({ :hostname => 'asdf' })
97
- expect(notice.hostname).to eq 'asdf'
98
- end
99
-
100
- it "defaults api key to configuration" do
101
- notice = build_notice
102
- expect(notice.api_key).to eq 'abc123def456'
103
- end
104
-
105
- it "sets the api key" do
106
- notice = build_notice({ :api_key => 'asdf' })
107
- expect(notice.api_key).to eq 'asdf'
108
- end
109
-
110
- context "custom fingerprint" do
111
- it "includes nil fingerprint when no fingerprint is specified" do
112
- notice = build_notice
113
- expect(notice.fingerprint).to be_nil
114
- end
115
-
116
- it "accepts fingerprint as string" do
117
- notice = build_notice({ :fingerprint => 'foo' })
118
- expect(notice.fingerprint).to eq '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
119
- end
120
-
121
- it "accepts fingerprint responding to #call" do
122
- notice = build_notice({ :fingerprint => double(:call => 'foo') })
123
- expect(notice.fingerprint).to eq '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
124
- end
125
-
126
- it "accepts fingerprint using #to_s" do
127
- notice = build_notice({ :fingerprint => double(:to_s => 'foo') })
128
- expect(notice.fingerprint).to eq '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33'
129
- end
130
- end
131
-
132
- context "with a backtrace" do
133
- before(:each) do
134
- @source = <<-RUBY
135
- $:<<'lib'
136
- require 'honeybadger'
137
-
138
- begin
139
- raise StandardError
140
- rescue => e
141
- puts Honeybadger::Notice.new(exception: e).backtrace.to_json
142
- end
143
- RUBY
144
-
145
- @backtrace_array = ["my/file/backtrace:3",
146
- "test/honeybadger/rack_test.rb:2:in `build_exception'",
147
- "test/honeybadger/rack_test.rb:52:in `test_delivers_exception_from_rack'",
148
- "foo/bar/baz.rb:28:in `run'"]
149
-
150
- @exception = build_exception
151
- @exception.set_backtrace(@backtrace_array)
152
- end
153
-
154
- it "passes its backtrace filters for parsing" do
155
- Honeybadger::Backtrace.should_receive(:parse).with(@backtrace_array, {:filters => 'foo'}).and_return(double(:lines => []))
156
-
157
- Honeybadger::Notice.new({:exception => @exception, :backtrace_filters => 'foo'})
158
- end
159
-
160
- it "passes its backtrace line filters for parsing" do
161
- @backtrace_array.each do |line|
162
- Honeybadger::Backtrace::Line.should_receive(:parse).with(line, {:filters => 'foo'})
163
- end
164
-
165
- Honeybadger::Notice.new({:exception => @exception, :backtrace_filters => 'foo'})
166
- end
167
-
168
- it "accepts a backtrace from an exception or hash" do
169
- backtrace = Honeybadger::Backtrace.parse(@backtrace_array)
170
- notice_from_exception = build_notice(:exception => @exception)
171
-
172
- expect(notice_from_exception.backtrace).to eq backtrace # backtrace was not correctly set from an exception
173
-
174
- notice_from_hash = build_notice(:backtrace => @backtrace_array)
175
- expect(notice_from_hash.backtrace).to eq backtrace # backtrace was not correctly set from a hash
176
- end
177
-
178
- context "without application trace" do
179
- before(:each) do
180
- Honeybadger.configuration.project_root = '/foo/bar'
181
- @string_io = StringIO.new(@source)
182
- File.stub(:exists?).with('my/file/backtrace').and_return true
183
- File.stub(:open).with('my/file/backtrace').and_yield @string_io
184
- end
185
-
186
- it "includes source extract from backtrace" do
187
- backtrace = Honeybadger::Backtrace.parse(@backtrace_array)
188
- notice_from_exception = build_notice(:exception => @exception)
189
- @string_io.rewind
190
-
191
- expect(notice_from_exception.source_extract).not_to be_empty # Expected backtrace source extract to be found
192
- expect(notice_from_exception.source_extract).to eq backtrace.lines.first.source
193
- end
194
- end
195
-
196
- context 'with an application trace' do
197
- before(:each) do
198
- Honeybadger.configuration.project_root = 'test/honeybadger/'
199
-
200
- @string_io = StringIO.new(@source)
201
- File.stub(:exists?).with('test/honeybadger/rack_test.rb').and_return true
202
- File.stub(:open).with('test/honeybadger/rack_test.rb').and_yield @string_io
203
- end
204
-
205
- it "includes source extract from first line of application trace" do
206
- backtrace = Honeybadger::Backtrace.parse(@backtrace_array)
207
- notice_from_exception = build_notice(:exception => @exception)
208
- @string_io.rewind
209
-
210
- expect(notice_from_exception.source_extract).not_to be_empty # Expected backtrace source extract to be found
211
- expect(notice_from_exception.source_extract).to eq backtrace.lines[1].source
212
- end
213
- end
214
- end
215
-
216
- it "Uses source extract from view when reporting an ActionView::Template::Error" do
217
- # TODO: I would like to stub out a real ActionView::Template::Error, but we're
218
- # currently locked at actionpack 2.3.8. Perhaps if one day we upgrade...
219
- source = <<-ERB
220
- 1: <%= current_user.name %>
221
- 2: </div>
222
- 3:
223
- 4: <div>
224
- ERB
225
- exception = build_exception
226
- exception.stub(:source_extract).and_return(source)
227
- notice = Honeybadger::Notice.new({:exception => exception})
228
-
229
- expect(notice.source_extract).to eq({ '1' => ' <%= current_user.name %>', '2' => '</div>', '3' => '', '4' => '<div>'})
230
- end
231
-
232
- it "sets the error class from an exception or hash" do
233
- assert_accepts_exception_attribute :error_class do |exception|
234
- exception.class.name
235
- end
236
- end
237
-
238
- it "sets the error message from an exception or hash" do
239
- assert_accepts_exception_attribute :error_message do |exception|
240
- "#{exception.class.name}: #{exception.message}"
241
- end
242
- end
243
-
244
- it "accepts parameters from a request or hash" do
245
- parameters = { 'one' => 'two' }
246
- notice_from_hash = build_notice(:parameters => parameters)
247
- expect(notice_from_hash.parameters).to eq parameters
248
- end
249
-
250
- it "accepts session data from a session[:data] hash" do
251
- data = { 'one' => 'two' }
252
- notice = build_notice(:session => { :data => data })
253
- expect(notice.session_data).to eq data
254
- end
255
-
256
- it "accepts session data from a session_data hash" do
257
- data = { 'one' => 'two' }
258
- notice = build_notice(:session_data => data)
259
- expect(notice.session_data).to eq data
260
- end
261
-
262
- it "accepts an environment name" do
263
- expect(build_notice(:environment_name => 'development').environment_name).to eq 'development'
264
- end
265
-
266
- it "accepts CGI data from a hash" do
267
- data = { 'STRING' => 'value' }
268
- notice = build_notice(:cgi_data => data)
269
- expect(notice.cgi_data).to eq data
270
- end
271
-
272
- it "accepts notifier information" do
273
- params = { :notifier_name => 'a name for a notifier',
274
- :notifier_version => '1.0.5',
275
- :notifier_url => 'http://notifiers.r.us/download' }
276
- notice = build_notice(params)
277
- expect(notice.notifier_name).to eq params[:notifier_name]
278
- expect(notice.notifier_version).to eq params[:notifier_version]
279
- expect(notice.notifier_url).to eq params[:notifier_url]
280
- end
281
-
282
- it "sets sensible defaults without an exception" do
283
- backtrace = Honeybadger::Backtrace.parse(build_backtrace_array)
284
- notice = build_notice(:backtrace => build_backtrace_array)
285
-
286
- expect(notice.error_message).to eq 'Notification'
287
- assert_array_starts_with backtrace.lines, notice.backtrace.lines
288
- expect(notice.parameters).to be_empty
289
- expect(notice.session_data).to be_empty
290
- end
291
-
292
- it "uses the caller as the backtrace for an exception without a backtrace" do
293
- filters = Honeybadger::Configuration.new.backtrace_filters
294
- backtrace = Honeybadger::Backtrace.parse(caller, :filters => filters)
295
- notice = build_notice(:exception => StandardError.new('error'), :backtrace => nil)
296
-
297
- assert_array_starts_with backtrace.lines, notice.backtrace.lines
298
- end
299
-
300
- it "removes non-uppercase keys" do
301
- original = {
302
- 'rack.request.form_vars' => 'story%5Btitle%5D=The+TODO+label',
303
- 'ABC' => "123"
304
- }
305
-
306
- notice = build_notice(:cgi_data => original)
307
- expect(notice.cgi_data).to eq({'ABC' => '123'})
308
- end
309
-
310
- it "does not send empty request data" do
311
- notice = build_notice
312
- notice.url.should be_nil
313
- notice.controller.should be_nil
314
- notice.action.should be_nil
315
-
316
- json = notice.to_json
317
- payload = JSON.parse(json)
318
- payload['request']['url'].should be_nil
319
- payload['request']['component'].should be_nil
320
- payload['request']['action'].should be_nil
321
- payload['request']['user'].should be_nil
322
- end
323
-
324
- %w(url controller action).each do |var|
325
- it "sends a request if #{var} is present" do
326
- notice = build_notice(var.to_sym => 'value')
327
- json = notice.to_json
328
- payload = JSON.parse(json)
329
- payload['request'].should_not be_nil
330
- end
331
- end
332
-
333
- %w(parameters cgi_data session_data context).each do |var|
334
- it "sends a request if #{var} is present" do
335
- notice = build_notice(var.to_sym => { 'key' => 'value' })
336
- json = notice.to_json
337
- payload = JSON.parse(json)
338
- payload['request'].should_not be_nil
339
- end
340
- end
341
-
342
- it "does not ignore an exception not matching ignore filters" do
343
- notice = build_notice(:error_class => 'ArgumentError',
344
- :ignore => ['Argument'],
345
- :ignore_by_filters => [lambda { |n| false }])
346
- expect(notice.ignore?).to be_false
347
- end
348
-
349
- it "ignores an exception with a matching error class" do
350
- notice = build_notice(:error_class => 'ArgumentError',
351
- :ignore => [ArgumentError])
352
- expect(notice.ignore?).to be_true
353
- end
354
-
355
- it "ignores an exception with an equal error class name" do
356
- notice = build_notice(:error_class => 'ArgumentError',
357
- :ignore => ['ArgumentError'])
358
- expect(notice.ignore?).to be_true # Expected ArgumentError to ignore ArgumentError
359
- end
360
-
361
- it "ignores an exception matching error class name" do
362
- notice = build_notice(:error_class => 'ArgumentError',
363
- :ignore => [/Error$/])
364
- expect(notice.ignore?).to be_true # Expected /Error$/ to ignore ArgumentError
365
- end
366
-
367
- it "ignores an exception that inherits from ignored error class" do
368
- class ::FooError < ArgumentError ; end
369
- notice = build_notice(:exception => FooError.new('Oh noes!'),
370
- :ignore => [ArgumentError])
371
- expect(notice.ignore?).to be_true # Expected ArgumentError to ignore FooError
372
- end
373
-
374
- it "ignores an exception with a matching filter" do
375
- filter = lambda {|notice| notice.error_class == 'ArgumentError' }
376
- notice = build_notice(:error_class => 'ArgumentError',
377
- :ignore_by_filters => [filter])
378
- expect(notice.ignore?).to be_true
379
- end
380
-
381
- it "does not raise without an ignore list" do
382
- notice = build_notice(:ignore => nil, :ignore_by_filters => nil)
383
- expect { notice.ignore? }.not_to raise_error
384
- end
385
-
386
- ignored_error_classes = %w(
387
- ActiveRecord::RecordNotFound
388
- AbstractController::ActionNotFound
389
- ActionController::RoutingError
390
- ActionController::InvalidAuthenticityToken
391
- CGI::Session::CookieStore::TamperedWithCookie
392
- ActionController::UnknownAction
393
- )
394
-
395
- ignored_error_classes.each do |ignored_error_class|
396
- it "ignores #{ignored_error_class} error by default" do
397
- notice = build_notice(:error_class => ignored_error_class)
398
- expect(notice.ignore?).to be_true
399
- end
400
- end
401
-
402
- it "acts like a hash" do
403
- notice = build_notice(:error_message => 'some message')
404
- expect(notice[:error_message]).to eq notice.error_message
405
- end
406
-
407
- it "returns params on notice[:request][:params]" do
408
- params = { 'one' => 'two' }
409
- notice = build_notice(:parameters => params)
410
- expect(notice[:request][:params]).to eq params
411
- end
412
-
413
- it "returns context on notice[:request][:context]" do
414
- context = { 'one' => 'two' }
415
- notice = build_notice(:context => context)
416
- expect(notice[:request][:context]).to eq context
417
- end
418
-
419
- it "merges context from args with context from Honeybadger#context" do
420
- Honeybadger.context({ 'one' => 'two', 'foo' => 'bar' })
421
- notice = build_notice(:context => { 'three' => 'four', 'foo' => 'baz' })
422
- expect(notice[:request][:context]).to eq({ 'one' => 'two', 'three' => 'four', 'foo' => 'baz' })
423
- end
424
-
425
- it "doesn't mutate global context" do
426
- Honeybadger.context({ 'one' => 'two' })
427
- expect { build_notice(:context => { 'foo' => 'bar' }) }.not_to change { Thread.current[:honeybadger_context] }
428
- end
429
-
430
- it "doesn't mutate local context" do
431
- Honeybadger.context({ 'one' => 'two' })
432
- hash = { 'foo' => 'bar' }
433
- expect { build_notice(:context => hash) }.not_to change { hash }
434
- end
435
-
436
- it "returns nil context when context is not set" do
437
- notice = build_notice
438
- notice[:request][:context].should be_nil
439
- end
440
-
441
- it "allows falsey values in context" do
442
- Honeybadger.context({ :debuga => true, :debugb => false })
443
- notice = build_notice
444
- hash = JSON.parse(notice.to_json)
445
- expect(hash['request']['context']).to eq({ 'debuga' => true, 'debugb' => false })
446
- end
447
-
448
- context "with a rack environment hash" do
449
- it "extracts data from a rack environment hash" do
450
- url = "https://subdomain.happylane.com:100/test/file.rb?var=value&var2=value2"
451
- parameters = { 'var' => 'value', 'var2' => 'value2' }
452
- env = Rack::MockRequest.env_for(url)
453
-
454
- notice = build_notice(:rack_env => env)
455
-
456
- expect(notice.url).to eq url
457
- expect(notice.parameters).to eq parameters
458
- expect(notice.cgi_data['REQUEST_METHOD']).to eq 'GET'
459
- end
460
-
461
- context "with action_dispatch info" do
462
- let(:params) { {'controller' => 'users', 'action' => 'index', 'id' => '7'} }
463
-
464
- it "extracts data from a rack environment hash " do
465
- env = Rack::MockRequest.env_for('/', { 'action_dispatch.request.parameters' => params })
466
- notice = build_notice(:rack_env => env)
467
-
468
- expect(notice.parameters).to eq params
469
- expect(notice.component).to eq params['controller']
470
- expect(notice.action).to eq params['action']
471
- end
472
-
473
- it "removes action_dispatch.request.parameters from cgi_data" do
474
- env = Rack::MockRequest.env_for('/', { 'action_dispatch.request.parameters' => params })
475
- notice = build_notice(:rack_env => env)
476
- expect(notice[:cgi_data]).not_to have_key 'action_dispatch.request.parameters'
477
- end
478
-
479
- it "removes action_dispatch.request.request_parameters from cgi_data" do
480
- env = Rack::MockRequest.env_for('/', { 'action_dispatch.request.request_parameters' => params })
481
- notice = build_notice(:rack_env => env)
482
- expect(notice[:cgi_data]).not_to have_key 'action_dispatch.request.request_parameters'
483
- end
484
- end
485
-
486
- it "extracts session data from a rack environment" do
487
- session_data = { 'something' => 'some value' }
488
- env = Rack::MockRequest.env_for('/', 'rack.session' => session_data)
489
-
490
- notice = build_notice(:rack_env => env)
491
-
492
- expect(notice.session_data).to eq session_data
493
- end
494
-
495
- it "prefers passed session data to rack session data" do
496
- session_data = { 'something' => 'some value' }
497
- env = Rack::MockRequest.env_for('/')
498
-
499
- notice = build_notice(:rack_env => env, :session_data => session_data)
500
-
501
- expect(notice.session_data).to eq session_data
502
- end
503
-
504
- if Gem::Version.new(Rack.release) < Gem::Version.new('1.3')
505
- it "parses params which are malformed in Rack >= 1.3" do
506
- rack_env = Rack::MockRequest.env_for('http://www.example.com/explode', :method => 'POST', :input => 'foo=bar&bar=baz%')
507
- expect { Honeybadger::Notice.new(:rack_env => rack_env) }.not_to raise_error
508
- end
509
- else
510
- it "fails gracefully when Rack params cannot be parsed" do
511
- rack_env = Rack::MockRequest.env_for('http://www.example.com/explode', :method => 'POST', :input => 'foo=bar&bar=baz%')
512
- notice = Honeybadger::Notice.new(:rack_env => rack_env)
513
- expect(notice.params.size).to eq 1
514
- expect(notice.params[:error]).to match(/Failed to call params on Rack::Request/)
515
- end
516
- end
517
- end
518
-
519
- it "does not send session data when send_request_session is false" do
520
- notice = build_notice(:send_request_session => false, :session_data => { :foo => :bar })
521
- notice.session_data.should be_nil
522
- end
523
-
524
- it "trims error message to 1k" do
525
- message = 'asdfghjkl'*200
526
- e = StandardError.new(message)
527
- notice = Honeybadger::Notice.new(:exception => e)
528
- message.bytesize.should > 1024
529
- expect(notice.error_message.bytesize).to eq 1024
530
- end
531
-
532
- it "prefers notice args to exception attributes" do
533
- e = RuntimeError.new('Not very helpful')
534
- notice = Honeybadger::Notice.new(:exception => e, :error_class => 'MyClass', :error_message => 'Something very specific went wrong.')
535
- expect(notice.error_class).to eq 'MyClass'
536
- expect(notice.error_message).to eq 'Something very specific went wrong.'
537
- end
538
-
539
- describe "#to_json" do
540
- context "when local variables are not found" do
541
- it "sends local_variables in request payload" do
542
- notice = build_notice
543
- hash = {'foo' => 'bar'}
544
- notice.stub(:local_variables).and_return(hash)
545
- expect(JSON.parse(notice.to_json)['request']['local_variables']).to eq(hash)
546
- end
547
- end
548
-
549
- context "when local variables are found" do
550
- it "sends local_variables in request payload" do
551
- notice = build_notice
552
- expect(JSON.parse(notice.to_json)['request']['local_variables']).to eq({})
553
- end
554
- end
555
- end
556
-
557
- describe "#local_variables" do
558
- let(:notice) { build_notice(:exception => @exception, :configuration => configuration) }
559
- let(:configuration) { configure }
560
-
561
- before do
562
- foo = 'bar'
563
- begin
564
- fail 'oops'
565
- rescue
566
- @exception = $!
567
- end
568
- end
569
-
570
- context "when binding_of_caller is not installed", :unless => defined?(BindingOfCaller) do
571
- context "when local variables aren't enabled" do
572
- it "does not attempt to find them" do
573
- expect(notice.local_variables).to eq({})
574
- end
575
- end
576
-
577
- context "when local variables are enabled" do
578
- before do
579
- configuration.send_local_variables = true
580
- end
581
-
582
- it "does not attempt to find them" do
583
- expect(notice.local_variables).to eq({})
584
- end
585
- end
586
- end
587
-
588
- context "when binding_of_caller is installed", :if => defined?(BindingOfCaller) do
589
- context "when local variables aren't enabled" do
590
- it "does not attempt to find them" do
591
- expect(notice.local_variables).to eq({})
592
- end
593
- end
594
-
595
- context "when local variables are enabled" do
596
- before do
597
- configuration.send_local_variables = true
598
- end
599
-
600
- it "finds the local variables from first frame of trace" do
601
- expect(notice.local_variables[:foo]).to eq 'bar'
602
- end
603
-
604
- context "when the feature is disabled" do
605
- before do
606
- configuration.features['local_variables'] = false
607
- end
608
-
609
- it "assigns empty Hash" do
610
- expect(notice.local_variables).to eq({})
611
- end
612
- end
613
-
614
- context "with an application trace" do
615
- before do
616
- @exception.__honeybadger_bindings_stack.unshift(double('Binding', :eval => nil))
617
- configuration.project_root = File.dirname(__FILE__)
618
- end
619
-
620
- it "finds the local variables from first frame of application trace" do
621
- expect(notice.local_variables[:foo]).to eq 'bar'
622
- end
623
-
624
- context "and project_root is a Pathname" do
625
- before do
626
- configuration.project_root = Pathname.new(File.dirname(__FILE__))
627
- end
628
-
629
- specify { expect { notice }.not_to raise_error }
630
- end
631
- end
632
-
633
- context "without an exception" do
634
- it "assigns empty Hash" do
635
- expect(build_notice(:exception => nil).local_variables).to eq({})
636
- end
637
- end
638
-
639
- context "without bindings" do
640
- it "assigns empty Hash" do
641
- expect(build_notice(:exception => RuntimeError.new).local_variables).to eq({})
642
- end
643
- end
644
- end
645
- end
646
- end
647
-
648
- def assert_accepts_exception_attribute(attribute, args = {}, &block)
649
- exception = build_exception
650
- block ||= lambda { exception.send(attribute) }
651
- value = block.call(exception)
652
-
653
- notice_from_exception = build_notice(args.merge(:exception => exception))
654
-
655
- expect(notice_from_exception.send(attribute)).to eq value
656
-
657
- notice_from_hash = build_notice(args.merge(attribute => value))
658
- expect(notice_from_hash.send(attribute)).to eq value
659
- end
660
-
661
- def build_backtrace_array
662
- ["app/models/user.rb:13:in `magic'",
663
- "app/controllers/users_controller.rb:8:in `index'"]
664
- end
665
-
666
- def hostname
667
- `hostname`.chomp
668
- end
669
- end