raygun4ruby 3.2.0 → 3.2.5.pre

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 (117) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +21 -18
  3. data/.rspec +1 -1
  4. data/.travis.yml +20 -12
  5. data/CHANGELOG.md +130 -117
  6. data/Gemfile +4 -4
  7. data/LICENSE.txt +22 -22
  8. data/README.md +420 -420
  9. data/Rakefile +27 -27
  10. data/examples/sinatras_raygun.rb +17 -17
  11. data/lib/generators/raygun/install_generator.rb +26 -26
  12. data/lib/raygun.rb +179 -179
  13. data/lib/raygun/affected_user.rb +59 -59
  14. data/lib/raygun/breadcrumbs.rb +34 -34
  15. data/lib/raygun/breadcrumbs/breadcrumb.rb +34 -34
  16. data/lib/raygun/breadcrumbs/store.rb +86 -86
  17. data/lib/raygun/client.rb +308 -303
  18. data/lib/raygun/configuration.rb +194 -194
  19. data/lib/raygun/error.rb +10 -10
  20. data/lib/raygun/javascript_tracker.rb +42 -42
  21. data/lib/raygun/middleware/breadcrumbs_store_initializer.rb +19 -19
  22. data/lib/raygun/middleware/javascript_exception_tracking.rb +32 -32
  23. data/lib/raygun/middleware/rack_exception_interceptor.rb +18 -18
  24. data/lib/raygun/middleware/rails_insert_affected_user.rb +26 -26
  25. data/lib/raygun/railtie.rb +39 -39
  26. data/lib/raygun/services/apply_whitelist_filter_to_payload.rb +27 -27
  27. data/lib/raygun/sidekiq.rb +71 -67
  28. data/lib/raygun/version.rb +3 -3
  29. data/lib/raygun4ruby.rb +1 -1
  30. data/lib/resque/failure/raygun.rb +25 -25
  31. data/lib/tasks/raygun.tasks +7 -7
  32. data/raygun4ruby.gemspec +45 -45
  33. data/spec/dummy/.gitignore +17 -0
  34. data/spec/dummy/Gemfile +47 -0
  35. data/spec/dummy/README.rdoc +28 -0
  36. data/spec/dummy/Rakefile +6 -6
  37. data/spec/dummy/app/assets/config/manifest.js +3 -3
  38. data/spec/dummy/app/assets/javascripts/application.js +13 -15
  39. data/spec/dummy/app/assets/stylesheets/application.css +15 -15
  40. data/spec/dummy/app/controllers/application_controller.rb +5 -2
  41. data/spec/dummy/app/controllers/home_controller.rb +4 -4
  42. data/spec/dummy/app/helpers/application_helper.rb +2 -2
  43. data/spec/dummy/app/{assets/javascripts/channels → mailers}/.keep +0 -0
  44. data/spec/dummy/{storage → app/models}/.keep +0 -0
  45. data/spec/dummy/app/views/home/index.html.erb +3 -3
  46. data/spec/dummy/app/views/home/index.json.erb +1 -1
  47. data/spec/dummy/app/views/layouts/application.html.erb +14 -15
  48. data/spec/dummy/bin/bundle +3 -3
  49. data/spec/dummy/bin/rails +9 -4
  50. data/spec/dummy/bin/rake +9 -4
  51. data/spec/dummy/bin/setup +29 -36
  52. data/spec/dummy/bin/spring +17 -0
  53. data/spec/dummy/config.ru +4 -5
  54. data/spec/dummy/config/application.rb +26 -18
  55. data/spec/dummy/config/boot.rb +3 -5
  56. data/spec/dummy/config/database.yml +25 -25
  57. data/spec/dummy/config/environment.rb +5 -5
  58. data/spec/dummy/config/environments/development.rb +41 -61
  59. data/spec/dummy/config/environments/production.rb +79 -94
  60. data/spec/dummy/config/initializers/assets.rb +11 -14
  61. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
  62. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -5
  63. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -4
  64. data/spec/dummy/config/initializers/inflections.rb +16 -16
  65. data/spec/dummy/config/initializers/mime_types.rb +4 -4
  66. data/spec/dummy/config/initializers/session_store.rb +3 -0
  67. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  68. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  69. data/spec/dummy/config/locales/en.yml +23 -33
  70. data/spec/dummy/config/routes.rb +58 -3
  71. data/spec/dummy/config/secrets.yml +22 -0
  72. data/spec/dummy/db/seeds.rb +7 -0
  73. data/spec/dummy/{db/test.sqlite3 → lib/tasks/.keep} +0 -0
  74. data/spec/dummy/public/404.html +67 -67
  75. data/spec/dummy/public/422.html +67 -67
  76. data/spec/dummy/public/500.html +66 -66
  77. data/spec/dummy/public/robots.txt +5 -0
  78. data/spec/dummy/{public/apple-touch-icon-precomposed.png → vendor/assets/javascripts/.keep} +0 -0
  79. data/spec/dummy/{public/apple-touch-icon.png → vendor/assets/stylesheets/.keep} +0 -0
  80. data/spec/features/javascript_spec.rb +48 -48
  81. data/spec/rails_helper.rb +4 -4
  82. data/spec/raygun/breadcrumbs/breadcrumb_spec.rb +171 -171
  83. data/spec/raygun/breadcrumbs/store_spec.rb +170 -170
  84. data/spec/raygun/raygun_spec.rb +47 -47
  85. data/spec/services/apply_whitelist_filter_to_payload_spec.rb +251 -251
  86. data/spec/spec_helper.rb +24 -24
  87. data/spec/support/fake_logger.rb +17 -17
  88. data/test/integration/client_test.rb +19 -19
  89. data/test/test_helper.rb +72 -72
  90. data/test/unit/affected_user_test.rb +136 -136
  91. data/test/unit/client_test.rb +812 -790
  92. data/test/unit/configuration_test.rb +206 -206
  93. data/test/unit/raygun_test.rb +25 -25
  94. data/test/unit/resque_failure_test.rb +24 -24
  95. data/test/unit/sidekiq_failure_test.rb +32 -32
  96. metadata +36 -49
  97. data/lib/raygun/testable.rb +0 -23
  98. data/spec/dummy/.ruby-version +0 -1
  99. data/spec/dummy/app/assets/javascripts/cable.js +0 -13
  100. data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
  101. data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
  102. data/spec/dummy/app/jobs/application_job.rb +0 -2
  103. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  104. data/spec/dummy/app/models/application_record.rb +0 -3
  105. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  106. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  107. data/spec/dummy/bin/update +0 -31
  108. data/spec/dummy/bin/yarn +0 -11
  109. data/spec/dummy/config/cable.yml +0 -10
  110. data/spec/dummy/config/environments/test.rb +0 -46
  111. data/spec/dummy/config/initializers/application_controller_renderer.rb +0 -8
  112. data/spec/dummy/config/initializers/content_security_policy.rb +0 -25
  113. data/spec/dummy/config/puma.rb +0 -34
  114. data/spec/dummy/config/spring.rb +0 -6
  115. data/spec/dummy/config/storage.yml +0 -34
  116. data/spec/dummy/db/schema.rb +0 -15
  117. data/spec/dummy/package.json +0 -5
@@ -1,790 +1,812 @@
1
- # -*- coding: utf-8 -*-
2
- require_relative "../test_helper.rb"
3
- require 'stringio'
4
-
5
- class ClientTest < Raygun::UnitTest
6
-
7
- class TestException < StandardError
8
- def initialize(message = nil)
9
- super(message || "A test message")
10
- end
11
- end
12
-
13
- class NilMessageError < StandardError
14
- def message
15
- nil
16
- end
17
- end
18
-
19
- class FakeActionDispatcherIp
20
- attr_reader :ip
21
- def initialize remote_ip
22
- @ip = remote_ip
23
- end
24
- def to_s
25
- return ip
26
- end
27
- end
28
-
29
- def setup
30
- super
31
- @client = Raygun::Client.new
32
- Raygun.configuration.record_raw_data = true
33
- fake_successful_entry
34
-
35
- # Force NZ time zone for utcOffset tests
36
- ENV['TZ'] = 'UTC-13'
37
- end
38
-
39
- def test_record_breadcrumb_does_not_crash_without_initialized_store
40
- Raygun.record_breadcrumb(
41
- message: 'aliens',
42
- category: 'exceptions',
43
- level: :info
44
- )
45
- end
46
-
47
- def test_api_key_required_message
48
- Raygun.configuration.api_key = nil
49
-
50
- $stderr.expects(:puts).with(Raygun::Client::NO_API_KEY_MESSAGE).once
51
- second_client = Raygun::Client.new
52
- end
53
-
54
- def test_track_exception
55
- response = Raygun.track_exceptions do
56
- raise TestException.new
57
- end
58
-
59
- assert response.success?
60
- end
61
-
62
- def test_error_details
63
- assert_equal exception_hash, @client.send(:error_details, test_exception)
64
- end
65
-
66
- def test_error_details_with_nil_message
67
- e = NilMessageError.new
68
- expected_message = ""
69
- assert_equal expected_message, @client.send(:error_details, e)[:message]
70
- end
71
-
72
- def test_utc_offset
73
- expected = 13
74
-
75
- assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:environment][:utcOffset]
76
- end
77
-
78
- def test_inner_error_details
79
- oe = TestException.new("A test message")
80
- oe.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'"])
81
-
82
- ie = TestException.new("Inner test message")
83
- ie.set_backtrace(["/another/path/foo.rb:1234:in `block (3 levels) run'"])
84
-
85
- e = nest_exceptions(oe, ie)
86
-
87
- expected_hash = {
88
- className: "ClientTest::TestException",
89
- message: oe.message,
90
- stackTrace: [
91
- { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" }
92
- ]
93
- }
94
-
95
- # test inner error according with its availability (ruby >= 2.1)
96
- if e.respond_to? :cause
97
- expected_hash[:innerError] = {
98
- className: "ClientTest::TestException",
99
- message: ie.message,
100
- stackTrace: [
101
- { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
102
- ]
103
- }
104
- end
105
-
106
- assert_equal expected_hash, @client.send(:error_details, e)
107
- end
108
-
109
- def test_client_details
110
- expected_hash = {
111
- name: Raygun::CLIENT_NAME,
112
- version: Raygun::VERSION,
113
- clientUrl: Raygun::CLIENT_URL
114
- }
115
-
116
- assert_equal expected_hash, @client.send(:client_details)
117
- end
118
-
119
-
120
- def test_version
121
- Raygun.setup do |config|
122
- config.version = 123
123
- end
124
-
125
- assert_equal 123, @client.send(:version)
126
- end
127
-
128
- def test_affected_user
129
- test_env = { "raygun.affected_user" => { :identifier => "somepooruser@yourapp.com" } }
130
- expected_hash = test_env["raygun.affected_user"]
131
-
132
- assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, test_env)[:details][:user]
133
- end
134
-
135
- def test_tags
136
- configuration_tags = %w{alpha beta gaga}
137
- explicit_env_tags = %w{one two three four}
138
- rack_env_tag = %w{test}
139
-
140
- Raygun.setup do |config|
141
- config.tags = configuration_tags
142
- end
143
-
144
- test_env = { tags: explicit_env_tags }
145
- expected_tags = configuration_tags + explicit_env_tags + rack_env_tag
146
-
147
- assert_equal expected_tags, @client.send(:build_payload_hash, test_exception, test_env)[:details][:tags]
148
- end
149
-
150
- def test_tags_with_proc
151
- configuration_tags = %w{bar}
152
- explicit_env_tags = %w{one two three four}
153
- rack_env_tag = %w{test}
154
-
155
- Raygun.setup do |config|
156
- config.tags = ->(exception, env) {
157
- [env[:foo]]
158
- }
159
- end
160
-
161
- test_env = { tags: explicit_env_tags, foo: 'bar' }
162
- expected_tags = configuration_tags + explicit_env_tags + rack_env_tag
163
-
164
- assert_equal expected_tags, @client.send(:build_payload_hash, test_exception, test_env)[:details][:tags]
165
- end
166
-
167
- def test_hostname
168
- assert_equal Socket.gethostname, @client.send(:hostname)
169
- end
170
-
171
- def test_unicode
172
- e = TestException.new('日本語のメッセージ です')
173
-
174
- assert_silent { @client.track_exception(e) }
175
- end
176
-
177
- def test_bad_encoding
178
- bad_message = (100..1000).to_a.pack('c*').force_encoding('utf-8')
179
- bad_exception = TestException.new(bad_message)
180
-
181
- assert !bad_message.valid_encoding?
182
- assert_silent { @client.track_exception(bad_exception) }
183
- end
184
-
185
- def test_backtrace_without_method_name
186
-
187
- expected = {
188
- lineNumber: "123",
189
- fileName: "/some/folder/some_file.rb",
190
- methodName: "(none)"
191
- }
192
-
193
- # note lack of "in method name" in this stack trace line
194
- assert_equal expected, @client.send(:stack_trace_for, "/some/folder/some_file.rb:123")
195
- end
196
-
197
- def test_full_payload_hash
198
- Timecop.freeze do
199
- Raygun.configuration.version = 123
200
- grouping_key = "my custom group"
201
-
202
- expected_hash = {
203
- occurredOn: Time.now.utc.iso8601,
204
- details: {
205
- machineName: Socket.gethostname,
206
- version: 123,
207
- client: {
208
- name: Raygun::CLIENT_NAME,
209
- version: Raygun::VERSION,
210
- clientUrl: Raygun::CLIENT_URL
211
- },
212
- error: exception_hash,
213
- userCustomData: {},
214
- tags: ["test"],
215
- request: {},
216
- groupingKey: grouping_key,
217
- environment: {
218
- utcOffset: 13
219
- }
220
- }
221
- }
222
-
223
- assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, { grouping_key: grouping_key })
224
- end
225
- end
226
-
227
- def test_getting_request_information
228
- env_hash = sample_env_hash.merge({
229
- "QUERY_STRING"=>"a=b&c=4945438",
230
- "REQUEST_URI"=>"/?a=b&c=4945438",
231
- })
232
-
233
- expected_hash = {
234
- hostName: "localhost",
235
- url: "/",
236
- httpMethod: "GET",
237
- iPAddress: "127.0.0.1",
238
- queryString: { "a" => "b", "c" => "4945438" },
239
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
240
- form: {},
241
- rawData: nil
242
- }
243
-
244
- assert_equal expected_hash, @client.send(:request_information, env_hash)
245
- end
246
-
247
- def test_getting_request_information_with_nil_env
248
- assert_equal({}, @client.send(:request_information, nil))
249
- end
250
-
251
- def test_raw_post_body
252
- env_hash = sample_env_hash.merge({
253
- "CONTENT_TYPE" => "application/json",
254
- "REQUEST_METHOD" => "POST",
255
- "rack.input" => StringIO.new('{"foo": "bar"}')
256
- })
257
-
258
- assert_equal '{"foo": "bar"}', @client.send(:request_information, env_hash)[:rawData]
259
- end
260
-
261
- def test_raw_post_body_with_more_than_4096_chars
262
- input = "0" * 5000;
263
- env_hash = sample_env_hash.merge({
264
- "CONTENT_TYPE" => "application/json",
265
- "REQUEST_METHOD" => "POST",
266
- "rack.input" => StringIO.new(input)
267
- })
268
-
269
- assert_equal input.slice(0, 4096), @client.send(:request_information, env_hash)[:rawData]
270
- end
271
-
272
- def test_raw_post_body_with_config_disabled
273
- Raygun.configuration.record_raw_data = false
274
- env_hash = sample_env_hash.merge({
275
- "CONTENT_TYPE" => "application/json",
276
- "REQUEST_METHOD" => "POST",
277
- "rack.input" => StringIO.new('{"foo": "bar"}')
278
- })
279
-
280
- assert_equal(nil, @client.send(:request_information, env_hash)[:rawData])
281
- end
282
-
283
- def test_error_raygun_custom_data
284
- custom_data = { "kappa" => "keepo" }
285
- e = Raygun::Error.new("A test message", custom_data)
286
- test_env = {}
287
- expected_form_hash = test_env.merge(custom_data)
288
-
289
- assert_equal expected_form_hash, @client.send(:build_payload_hash, e, test_env)[:details][:userCustomData]
290
- end
291
-
292
- def test_custom_data_configuration_with_hash
293
- custom_data = {foo: '123'}
294
- Raygun.configuration.custom_data = custom_data
295
-
296
- assert_equal custom_data, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
297
- end
298
-
299
- def test_custom_data_configuration_with_proc
300
- Raygun.configuration.custom_data do |exception, env|
301
- {exception_message: exception.message, server_name: env["SERVER_NAME"]}
302
- end
303
- expected = {
304
- exception_message: "A test message",
305
- server_name: "localhost"
306
- }
307
-
308
- assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
309
- end
310
-
311
- def test_filtering_parameters
312
- post_body_env_hash = sample_env_hash.merge(
313
- "REQUEST_METHOD" => "POST",
314
- "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
315
- )
316
-
317
- expected_form_hash = { "a" => "b", "c" => "4945438", "password" => "[FILTERED]" }
318
-
319
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
320
- end
321
-
322
- def test_filtering_nested_params
323
- post_body_env_hash = sample_env_hash.merge(
324
- "REQUEST_METHOD" => "POST",
325
- "rack.input" => StringIO.new("a=b&bank%5Bcredit_card%5D%5Bcard_number%5D=my_secret_bank_number&bank%5Bname%5D=something&c=123456&user%5Bpassword%5D=my_fancy_password")
326
- )
327
-
328
- expected_form_hash = { "a" => "b", "bank" => { "credit_card" => { "card_number" => "[FILTERED]" }, "name" => "something" }, "c" => "123456", "user" => { "password" => "[FILTERED]" } }
329
-
330
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
331
- end
332
-
333
- def test_filter_parameters_using_proc
334
- # filter any parameters that start with "nsa_only"
335
- Raygun.configuration.filter_parameters do |hash|
336
- hash.inject({}) do |sanitized_hash, (k, v)|
337
- sanitized_hash[k] = if k.start_with? "nsa_only"
338
- "[OUREYESONLY]"
339
- else
340
- v
341
- end
342
- sanitized_hash
343
- end
344
- end
345
-
346
- post_body_env_hash = sample_env_hash.merge(
347
- "REQUEST_METHOD" => "POST",
348
- "rack.input" => StringIO.new("nsa_only_info=123&nsa_only_metadata=seekrit&something_normal=hello")
349
- )
350
-
351
- expected_form_hash = { "nsa_only_info" => "[OUREYESONLY]", "nsa_only_metadata" => "[OUREYESONLY]", "something_normal" => "hello" }
352
-
353
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
354
- ensure
355
- Raygun.configuration.filter_parameters = nil
356
- end
357
-
358
- def test_filter_parameters_using_array
359
- filter_params_as_from_rails = [:password]
360
- Raygun.configuration.filter_parameters = filter_params_as_from_rails
361
-
362
- parameters = {
363
- "something_normal" => "hello",
364
- "password" => "wouldntyouliketoknow",
365
- "password_confirmation" => "wouldntyouliketoknow",
366
- "PasswORD_weird_case" => "anythingatall"
367
- }
368
-
369
- expected_form_hash = {
370
- "something_normal" => "hello",
371
- "password" => "[FILTERED]",
372
- "password_confirmation" => "[FILTERED]",
373
- "PasswORD_weird_case" => "[FILTERED]"
374
- }
375
-
376
- post_body_env_hash = sample_env_hash.merge(
377
- "REQUEST_METHOD" => "POST",
378
- "rack.input" => StringIO.new(URI.encode_www_form(parameters))
379
- )
380
-
381
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
382
- ensure
383
- Raygun.configuration.filter_parameters = nil
384
- end
385
-
386
- def test_ip_address_from_action_dispatch
387
- env_hash = sample_env_hash.merge({
388
- "action_dispatch.remote_ip"=> "123.456.789.012"
389
- })
390
-
391
- assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
392
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
393
- end
394
-
395
- def test_ip_address_from_old_action_dispatch
396
- old_action_dispatch_ip = FakeActionDispatcherIp.new("123.456.789.012")
397
- env_hash = sample_env_hash.merge({
398
- "action_dispatch.remote_ip"=> old_action_dispatch_ip
399
- })
400
-
401
- assert_equal old_action_dispatch_ip, @client.send(:ip_address_from, env_hash)
402
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
403
- end
404
-
405
- def test_ip_address_from_raygun_specific_key
406
- env_hash = sample_env_hash.merge({
407
- "raygun.remote_ip"=>"123.456.789.012"
408
- })
409
-
410
- assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
411
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
412
- end
413
-
414
- def test_ip_address_returns_not_available_if_not_set
415
- env_hash = sample_env_hash.dup
416
- env_hash.delete("REMOTE_ADDR")
417
-
418
- assert_equal "(Not Available)", @client.send(:ip_address_from, env_hash)
419
- end
420
-
421
- def test_setting_up_http_proxy
422
- begin
423
- Raygun.configuration.proxy_settings[:address] = "http://proxy.com"
424
- Raygun::Client.expects(:http_proxy).with("http://proxy.com", "80", nil, nil)
425
-
426
- Raygun.track_exceptions do
427
- raise TestException.new
428
- end
429
- ensure
430
- Raygun.configuration.proxy_settings = {}
431
- end
432
- end
433
-
434
- def test_filter_payload_with_whitelist_never_filters_toplevel
435
- Timecop.freeze do
436
- Raygun.configuration.filter_payload_with_whitelist = true
437
- Raygun.configuration.whitelist_payload_shape = {}
438
-
439
- e = test_exception
440
-
441
- assert_equal Time.now.utc.iso8601, @client.send(:build_payload_hash, e)[:occurredOn]
442
- assert_equal Hash, @client.send(:build_payload_hash, e)[:details].class
443
- end
444
- end
445
-
446
- def test_filter_payload_with_whitelist_never_filters_client
447
- Raygun.configuration.filter_payload_with_whitelist = true
448
- Raygun.configuration.whitelist_payload_shape = {}
449
-
450
- client_details = @client.send(:client_details)
451
-
452
- assert_equal client_details, @client.send(:build_payload_hash, test_exception)[:details][:client]
453
- end
454
-
455
- def test_filter_payload_with_whitelist_default_error
456
- Raygun.configuration.filter_payload_with_whitelist = true
457
-
458
- details = @client.send(:build_payload_hash, test_exception)[:details]
459
-
460
- assert_equal exception_hash, details[:error]
461
- end
462
-
463
- def test_filter_payload_with_whitelist_exclude_error_keys
464
- Raygun.configuration.filter_payload_with_whitelist = true
465
- Raygun.configuration.whitelist_payload_shape = {
466
- error: {
467
- className: true,
468
- message: true,
469
- stackTrace: true
470
- }
471
- }
472
-
473
- details = @client.send(:build_payload_hash, test_exception)[:details]
474
-
475
- assert_equal exception_hash, details[:error]
476
- end
477
-
478
- def test_filter_payload_with_whitelist_exclude_error_except_stacktrace
479
- Raygun.configuration.filter_payload_with_whitelist = true
480
- Raygun.configuration.whitelist_payload_shape = {
481
- error: {
482
- className: true,
483
- message: true,
484
- }
485
- }
486
-
487
- details = @client.send(:build_payload_hash, test_exception)[:details]
488
-
489
- expected_hash = exception_hash.merge({
490
- stackTrace: "[FILTERED]"
491
- })
492
-
493
- assert_equal expected_hash, details[:error]
494
- end
495
-
496
- def test_filter_payload_with_whitelist_proc
497
- Raygun.configuration.filter_payload_with_whitelist = true
498
- Raygun.configuration.whitelist_payload_shape do |payload|
499
- payload
500
- end
501
-
502
- details = @client.send(:build_payload_hash, test_exception)[:details]
503
-
504
- assert_equal exception_hash, details[:error]
505
- end
506
-
507
- def test_filter_payload_with_whitelist_default_request_post
508
- Raygun.configuration.filter_payload_with_whitelist = true
509
-
510
- post_body_env_hash = sample_env_hash.merge(
511
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
512
- "REQUEST_METHOD" => "POST",
513
- "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
514
- )
515
-
516
- details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
517
-
518
- expected_hash = {
519
- hostName: "localhost",
520
- url: "/",
521
- httpMethod: "POST",
522
- iPAddress: "127.0.0.1",
523
- queryString: { },
524
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
525
- form: { "a" => "[FILTERED]", "c" => "[FILTERED]", "password" => "[FILTERED]" },
526
- rawData: {}
527
- }
528
-
529
- assert_equal expected_hash, details[:request]
530
- end
531
-
532
- def test_filter_payload_with_whitelist_request_post_except_formkey
533
- Raygun.configuration.filter_payload_with_whitelist = true
534
- shape = Raygun.configuration.whitelist_payload_shape.dup
535
- shape[:request] = Raygun.configuration.whitelist_payload_shape[:request].merge(
536
- form: {
537
- username: true
538
- }
539
- )
540
- Raygun.configuration.whitelist_payload_shape = shape
541
-
542
- post_body_env_hash = sample_env_hash.merge(
543
- "REQUEST_METHOD" => "POST",
544
- "rack.input"=>StringIO.new("username=foo&password=swordfish")
545
- )
546
-
547
- details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
548
-
549
- expected_hash = {
550
- hostName: "localhost",
551
- url: "/",
552
- httpMethod: "POST",
553
- iPAddress: "127.0.0.1",
554
- queryString: { },
555
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
556
- form: { "username" => "foo", "password" => "[FILTERED]" },
557
- rawData: {}
558
- }
559
-
560
- assert_equal expected_hash, details[:request]
561
- end
562
-
563
- def test_filter_payload_with_whitelist_default_request_get
564
- Raygun.configuration.filter_payload_with_whitelist = true
565
-
566
- env_hash = sample_env_hash.merge({
567
- "QUERY_STRING"=>"a=b&c=4945438",
568
- "REQUEST_URI"=>"/?a=b&c=4945438",
569
- })
570
- expected_hash = {
571
- hostName: "localhost",
572
- url: "/",
573
- httpMethod: "GET",
574
- iPAddress: "127.0.0.1",
575
- queryString: { "a" => "b", "c" => "4945438" },
576
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
577
- form: {},
578
- rawData: nil
579
- }
580
-
581
- details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
582
-
583
- assert_equal expected_hash, details[:request]
584
- end
585
-
586
- def test_filter_payload_with_whitelist_default_request_get_except_querystring
587
- Raygun.configuration.filter_payload_with_whitelist = true
588
- shape = Raygun.configuration.whitelist_payload_shape.dup
589
- shape[:request] = Raygun::Configuration::DEFAULT_WHITELIST_PAYLOAD_SHAPE_REQUEST.dup.tap do |h|
590
- h.delete(:queryString)
591
- end
592
- Raygun.configuration.whitelist_payload_shape = shape
593
-
594
- expected_hash = {
595
- hostName: "localhost",
596
- url: "/",
597
- httpMethod: "GET",
598
- iPAddress: "127.0.0.1",
599
- queryString: "[FILTERED]",
600
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
601
- form: {},
602
- rawData: nil
603
- }
604
-
605
- details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
606
-
607
- assert_equal expected_hash, details[:request]
608
- end
609
-
610
- def test_filter_payload_with_whitelist_being_false_does_not_filter_query_string
611
- Raygun.configuration.filter_payload_with_whitelist = false
612
-
613
- env_hash = sample_env_hash.merge({
614
- "QUERY_STRING"=>"a=b&c=4945438",
615
- "REQUEST_URI"=>"/?a=b&c=4945438",
616
- })
617
- expected_hash = {
618
- hostName: "localhost",
619
- url: "/",
620
- httpMethod: "GET",
621
- iPAddress: "127.0.0.1",
622
- queryString: { "a" => "b", "c" => "4945438" },
623
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
624
- form: {},
625
- rawData: nil
626
- }
627
-
628
- details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
629
-
630
- assert_equal expected_hash, details[:request]
631
- end
632
-
633
- def test_filter_payload_with_whitelist_request_specific_keys
634
- Raygun.configuration.filter_payload_with_whitelist = true
635
- Raygun.configuration.whitelist_payload_shape = {
636
- request: {
637
- url: true,
638
- httpMethod: true,
639
- hostName: true
640
- }
641
- }
642
-
643
- details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
644
-
645
- expected_hash = {
646
- hostName: "localhost",
647
- url: "/",
648
- httpMethod: "GET",
649
- iPAddress: "[FILTERED]",
650
- queryString: "[FILTERED]",
651
- headers: "[FILTERED]",
652
- form: "[FILTERED]",
653
- rawData: "[FILTERED]"
654
- }
655
-
656
- assert_equal expected_hash, details[:request]
657
- end
658
-
659
-
660
- def test_filter_payload_with_whitelist_and_filter_parameters_applies_both
661
- Raygun.configuration.filter_parameters = [:password]
662
- Raygun.configuration.filter_payload_with_whitelist = true
663
- Raygun.configuration.whitelist_payload_shape = proc do |payload|
664
- payload[:request][:headers]["Cookie"] = "[FILTERED]"
665
- payload
666
- end
667
-
668
- parameters = {
669
- "something_normal" => "hello",
670
- "password" => "wouldntyouliketoknow"
671
- }
672
-
673
- post_body_env_hash = sample_env_hash.merge(
674
- "REQUEST_METHOD" => "POST",
675
- "rack.input" => StringIO.new(URI.encode_www_form(parameters))
676
- )
677
-
678
- payload = @client.send(:build_payload_hash, test_exception, post_body_env_hash)
679
- request_payload = payload[:details][:request]
680
-
681
- expected_form = {
682
- "something_normal" => "hello",
683
- "password" => "[FILTERED]"
684
- }
685
-
686
- assert_equal expected_form, request_payload[:form]
687
-
688
- expected_headers = {
689
- "Version" => "HTTP/1.1",
690
- "Host" => "localhost:3000",
691
- "Cookie" => "[FILTERED]"
692
- }
693
-
694
- assert_equal expected_headers, request_payload[:headers]
695
- end
696
-
697
- def test_build_payload_hash_adds_affected_user_details_when_supplied_with_user
698
- user = OpenStruct.new(id: '123', email: 'test@email.com', first_name: 'Taylor')
699
- expected_details = {
700
- :isAnonymous => false,
701
- :identifier => '123',
702
- :email => 'test@email.com',
703
- :firstName => 'Taylor',
704
- }
705
-
706
- user_details = @client.send(:build_payload_hash, test_exception, sample_env_hash, user)[:details][:user]
707
-
708
- assert_equal expected_details, user_details
709
- end
710
-
711
- def test_build_payload_includes_breadcrumbs
712
- ::Raygun::Breadcrumbs::Store.initialize
713
- ::Raygun::Breadcrumbs::Store.record(message: "foo")
714
-
715
- breadcrumbs = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:breadcrumbs]
716
- ::Raygun::Breadcrumbs::Store.clear
717
-
718
- assert_equal breadcrumbs.length, 1
719
- assert breadcrumbs[0].is_a? Hash
720
- end
721
-
722
- def test_raw_data_does_not_crash_on_buffer_without_pos
723
- buffer = StringIO.new('123456789')
724
- rack_env = {
725
- REQUEST_METHOD: 'POST',
726
- 'rack.input' => buffer
727
- }
728
-
729
- buffer.instance_eval('undef :pos')
730
-
731
- raw_data = @client.send(:raw_data, rack_env)
732
-
733
- assert_equal('123456789', raw_data)
734
- end
735
-
736
- private
737
-
738
- def test_exception
739
- e = TestException.new
740
- e.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'",
741
- "/another/path/foo.rb:1234:in `block (3 levels) run'"])
742
-
743
- e
744
- end
745
-
746
- def nest_exceptions(outer_exception, inner_exception)
747
- begin
748
- begin
749
- raise inner_exception.class, inner_exception.message
750
- rescue => e
751
- e.set_backtrace inner_exception.backtrace
752
- raise outer_exception.class, outer_exception.message
753
- end
754
- rescue => nested_exception
755
- nested_exception.set_backtrace outer_exception.backtrace
756
- end
757
-
758
- nested_exception
759
- end
760
-
761
- def exception_hash
762
- {
763
- className: "ClientTest::TestException",
764
- message: "A test message",
765
- stackTrace: [
766
- { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" },
767
- { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
768
- ]
769
- }
770
- end
771
-
772
- def sample_env_hash
773
- {
774
- "SERVER_NAME"=>"localhost",
775
- "REQUEST_METHOD"=>"GET",
776
- "REQUEST_PATH"=>"/",
777
- "PATH_INFO"=>"/",
778
- "QUERY_STRING"=>"",
779
- "REQUEST_URI"=>"/",
780
- "HTTP_VERSION"=>"HTTP/1.1",
781
- "HTTP_HOST"=>"localhost:3000",
782
- "HTTP_COOKIE"=>"cookieval",
783
- "GATEWAY_INTERFACE"=>"CGI/1.2",
784
- "SERVER_PORT"=>"3000",
785
- "SERVER_PROTOCOL"=>"HTTP/1.1",
786
- "SCRIPT_NAME"=>"",
787
- "REMOTE_ADDR"=>"127.0.0.1"
788
- }
789
- end
790
- end
1
+ # -*- coding: utf-8 -*-
2
+ require_relative "../test_helper.rb"
3
+ require 'stringio'
4
+
5
+ class ClientTest < Raygun::UnitTest
6
+
7
+ class TestException < StandardError
8
+ def initialize(message = nil)
9
+ super(message || "A test message")
10
+ end
11
+ end
12
+
13
+ class NilMessageError < StandardError
14
+ def message
15
+ nil
16
+ end
17
+ end
18
+
19
+ class FakeActionDispatcherIp
20
+ attr_reader :ip
21
+ def initialize remote_ip
22
+ @ip = remote_ip
23
+ end
24
+ def to_s
25
+ return ip
26
+ end
27
+ end
28
+
29
+ def setup
30
+ super
31
+ @client = Raygun::Client.new
32
+ Raygun.configuration.record_raw_data = true
33
+ fake_successful_entry
34
+
35
+ # Force NZ time zone for utcOffset tests
36
+ ENV['TZ'] = 'UTC-13'
37
+ end
38
+
39
+ def test_record_breadcrumb_does_not_crash_without_initialized_store
40
+ Raygun.record_breadcrumb(
41
+ message: 'aliens',
42
+ category: 'exceptions',
43
+ level: :info
44
+ )
45
+ end
46
+
47
+ def test_api_key_required_message
48
+ Raygun.configuration.api_key = nil
49
+
50
+ $stderr.expects(:puts).with(Raygun::Client::NO_API_KEY_MESSAGE).once
51
+ second_client = Raygun::Client.new
52
+ end
53
+
54
+ def test_track_exception
55
+ response = Raygun.track_exceptions do
56
+ raise TestException.new
57
+ end
58
+
59
+ assert response.success?
60
+ end
61
+
62
+ def test_error_details
63
+ assert_equal exception_hash, @client.send(:error_details, test_exception)
64
+ end
65
+
66
+ def test_error_details_with_nil_message
67
+ e = NilMessageError.new
68
+ expected_message = ""
69
+ assert_equal expected_message, @client.send(:error_details, e)[:message]
70
+ end
71
+
72
+ def test_utc_offset
73
+ expected = 13
74
+
75
+ assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:environment][:utcOffset]
76
+ end
77
+
78
+ def test_inner_error_details
79
+ oe = TestException.new("A test message")
80
+ oe.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'"])
81
+
82
+ ie = TestException.new("Inner test message")
83
+ ie.set_backtrace(["/another/path/foo.rb:1234:in `block (3 levels) run'"])
84
+
85
+ e = nest_exceptions(oe, ie)
86
+
87
+ expected_hash = {
88
+ className: "ClientTest::TestException",
89
+ message: oe.message,
90
+ stackTrace: [
91
+ { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" }
92
+ ]
93
+ }
94
+
95
+ # test inner error according with its availability (ruby >= 2.1)
96
+ if e.respond_to? :cause
97
+ expected_hash[:innerError] = {
98
+ className: "ClientTest::TestException",
99
+ message: ie.message,
100
+ stackTrace: [
101
+ { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
102
+ ]
103
+ }
104
+ end
105
+
106
+ assert_equal expected_hash, @client.send(:error_details, e)
107
+ end
108
+
109
+ def test_client_details
110
+ expected_hash = {
111
+ name: Raygun::CLIENT_NAME,
112
+ version: Raygun::VERSION,
113
+ clientUrl: Raygun::CLIENT_URL
114
+ }
115
+
116
+ assert_equal expected_hash, @client.send(:client_details)
117
+ end
118
+
119
+
120
+ def test_version
121
+ Raygun.setup do |config|
122
+ config.version = 123
123
+ end
124
+
125
+ assert_equal 123, @client.send(:version)
126
+ end
127
+
128
+ def test_affected_user
129
+ test_env = { "raygun.affected_user" => { :identifier => "somepooruser@yourapp.com" } }
130
+ expected_hash = test_env["raygun.affected_user"]
131
+
132
+ assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, test_env)[:details][:user]
133
+ end
134
+
135
+ def test_tags
136
+ configuration_tags = %w[alpha beta gaga]
137
+ explicit_env_tags = %w[one two three four]
138
+ rack_env_tag = %w[test]
139
+
140
+ Raygun.setup do |config|
141
+ config.tags = configuration_tags
142
+ end
143
+
144
+ test_env = { tags: explicit_env_tags }
145
+ expected_tags = configuration_tags + explicit_env_tags + rack_env_tag
146
+
147
+ assert_equal expected_tags, @client.send(:build_payload_hash, test_exception, test_env)[:details][:tags]
148
+ end
149
+
150
+ def test_tags_with_proc
151
+ configuration_tags = %w[bar]
152
+ explicit_env_tags = %w[one two three four]
153
+ rack_env_tag = %w[test]
154
+
155
+ Raygun.setup do |config|
156
+ config.tags = ->(exception, env) {
157
+ [env[:foo]]
158
+ }
159
+ end
160
+
161
+ test_env = { tags: explicit_env_tags, foo: 'bar' }
162
+ expected_tags = configuration_tags + explicit_env_tags + rack_env_tag
163
+
164
+ assert_equal expected_tags, @client.send(:build_payload_hash, test_exception, test_env)[:details][:tags]
165
+ end
166
+
167
+ def test_tags_with_multiple_send_calls
168
+ configuration_tags = %w[config-tag]
169
+ explicit_env_tags = %w[explicit-env-tag]
170
+ rack_env_tag = %w[test]
171
+
172
+ Raygun.setup do |config|
173
+ config.tags = configuration_tags
174
+ end
175
+
176
+ test_env = { tags: explicit_env_tags }
177
+ expected_tags_1 = configuration_tags + explicit_env_tags + rack_env_tag
178
+
179
+ assert_equal expected_tags_1, @client.send(:build_payload_hash, test_exception, test_env)[:details][:tags]
180
+
181
+ # Tags passed in via the `env` parameter should not persist once the crash report has been sent
182
+ expected_tags_2 = configuration_tags + rack_env_tag
183
+
184
+ assert_equal expected_tags_2, @client.send(:build_payload_hash, test_exception)[:details][:tags]
185
+ end
186
+
187
+ def test_hostname
188
+ assert_equal Socket.gethostname, @client.send(:hostname)
189
+ end
190
+
191
+ def test_unicode
192
+ e = TestException.new('日本語のメッセージ です')
193
+
194
+ assert_silent { @client.track_exception(e) }
195
+ end
196
+
197
+ def test_bad_encoding
198
+ bad_message = (100..1000).to_a.pack('c*').force_encoding('utf-8')
199
+ bad_exception = TestException.new(bad_message)
200
+
201
+ assert !bad_message.valid_encoding?
202
+ assert_silent { @client.track_exception(bad_exception) }
203
+ end
204
+
205
+ def test_backtrace_without_method_name
206
+
207
+ expected = {
208
+ lineNumber: "123",
209
+ fileName: "/some/folder/some_file.rb",
210
+ methodName: "(none)"
211
+ }
212
+
213
+ # note lack of "in method name" in this stack trace line
214
+ assert_equal expected, @client.send(:stack_trace_for, "/some/folder/some_file.rb:123")
215
+ end
216
+
217
+ def test_full_payload_hash
218
+ Timecop.freeze do
219
+ Raygun.configuration.version = 123
220
+ grouping_key = "my custom group"
221
+ correlation_id = "my correlation id"
222
+
223
+ expected_hash = {
224
+ occurredOn: Time.now.utc.iso8601,
225
+ details: {
226
+ machineName: Socket.gethostname,
227
+ version: 123,
228
+ client: {
229
+ name: Raygun::CLIENT_NAME,
230
+ version: Raygun::VERSION,
231
+ clientUrl: Raygun::CLIENT_URL
232
+ },
233
+ error: exception_hash,
234
+ userCustomData: {},
235
+ tags: ["test"],
236
+ request: {},
237
+ groupingKey: grouping_key,
238
+ correlationId: correlation_id,
239
+ environment: {
240
+ utcOffset: 13
241
+ }
242
+ }
243
+ }
244
+
245
+ assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, { grouping_key: grouping_key, correlation_id: correlation_id })
246
+ end
247
+ end
248
+
249
+ def test_getting_request_information
250
+ env_hash = sample_env_hash.merge({
251
+ "QUERY_STRING"=>"a=b&c=4945438",
252
+ "REQUEST_URI"=>"/?a=b&c=4945438",
253
+ })
254
+
255
+ expected_hash = {
256
+ hostName: "localhost",
257
+ url: "/",
258
+ httpMethod: "GET",
259
+ iPAddress: "127.0.0.1",
260
+ queryString: { "a" => "b", "c" => "4945438" },
261
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
262
+ form: {},
263
+ rawData: nil
264
+ }
265
+
266
+ assert_equal expected_hash, @client.send(:request_information, env_hash)
267
+ end
268
+
269
+ def test_getting_request_information_with_nil_env
270
+ assert_equal({}, @client.send(:request_information, nil))
271
+ end
272
+
273
+ def test_raw_post_body
274
+ env_hash = sample_env_hash.merge({
275
+ "CONTENT_TYPE" => "application/json",
276
+ "REQUEST_METHOD" => "POST",
277
+ "rack.input" => StringIO.new('{"foo": "bar"}')
278
+ })
279
+
280
+ assert_equal '{"foo": "bar"}', @client.send(:request_information, env_hash)[:rawData]
281
+ end
282
+
283
+ def test_raw_post_body_with_more_than_4096_chars
284
+ input = "0" * 5000;
285
+ env_hash = sample_env_hash.merge({
286
+ "CONTENT_TYPE" => "application/json",
287
+ "REQUEST_METHOD" => "POST",
288
+ "rack.input" => StringIO.new(input)
289
+ })
290
+
291
+ assert_equal input.slice(0, 4096), @client.send(:request_information, env_hash)[:rawData]
292
+ end
293
+
294
+ def test_raw_post_body_with_config_disabled
295
+ Raygun.configuration.record_raw_data = false
296
+ env_hash = sample_env_hash.merge({
297
+ "CONTENT_TYPE" => "application/json",
298
+ "REQUEST_METHOD" => "POST",
299
+ "rack.input" => StringIO.new('{"foo": "bar"}')
300
+ })
301
+
302
+ assert_equal(nil, @client.send(:request_information, env_hash)[:rawData])
303
+ end
304
+
305
+ def test_error_raygun_custom_data
306
+ custom_data = { "kappa" => "keepo" }
307
+ e = Raygun::Error.new("A test message", custom_data)
308
+ test_env = {}
309
+ expected_form_hash = test_env.merge(custom_data)
310
+
311
+ assert_equal expected_form_hash, @client.send(:build_payload_hash, e, test_env)[:details][:userCustomData]
312
+ end
313
+
314
+ def test_custom_data_configuration_with_hash
315
+ custom_data = {foo: '123'}
316
+ Raygun.configuration.custom_data = custom_data
317
+
318
+ assert_equal custom_data, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
319
+ end
320
+
321
+ def test_custom_data_configuration_with_proc
322
+ Raygun.configuration.custom_data do |exception, env|
323
+ {exception_message: exception.message, server_name: env["SERVER_NAME"]}
324
+ end
325
+ expected = {
326
+ exception_message: "A test message",
327
+ server_name: "localhost"
328
+ }
329
+
330
+ assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
331
+ end
332
+
333
+ def test_filtering_parameters
334
+ post_body_env_hash = sample_env_hash.merge(
335
+ "REQUEST_METHOD" => "POST",
336
+ "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
337
+ )
338
+
339
+ expected_form_hash = { "a" => "b", "c" => "4945438", "password" => "[FILTERED]" }
340
+
341
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
342
+ end
343
+
344
+ def test_filtering_nested_params
345
+ post_body_env_hash = sample_env_hash.merge(
346
+ "REQUEST_METHOD" => "POST",
347
+ "rack.input" => StringIO.new("a=b&bank%5Bcredit_card%5D%5Bcard_number%5D=my_secret_bank_number&bank%5Bname%5D=something&c=123456&user%5Bpassword%5D=my_fancy_password")
348
+ )
349
+
350
+ expected_form_hash = { "a" => "b", "bank" => { "credit_card" => { "card_number" => "[FILTERED]" }, "name" => "something" }, "c" => "123456", "user" => { "password" => "[FILTERED]" } }
351
+
352
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
353
+ end
354
+
355
+ def test_filter_parameters_using_proc
356
+ # filter any parameters that start with "nsa_only"
357
+ Raygun.configuration.filter_parameters do |hash|
358
+ hash.inject({}) do |sanitized_hash, (k, v)|
359
+ sanitized_hash[k] = if k.start_with? "nsa_only"
360
+ "[OUREYESONLY]"
361
+ else
362
+ v
363
+ end
364
+ sanitized_hash
365
+ end
366
+ end
367
+
368
+ post_body_env_hash = sample_env_hash.merge(
369
+ "REQUEST_METHOD" => "POST",
370
+ "rack.input" => StringIO.new("nsa_only_info=123&nsa_only_metadata=seekrit&something_normal=hello")
371
+ )
372
+
373
+ expected_form_hash = { "nsa_only_info" => "[OUREYESONLY]", "nsa_only_metadata" => "[OUREYESONLY]", "something_normal" => "hello" }
374
+
375
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
376
+ ensure
377
+ Raygun.configuration.filter_parameters = nil
378
+ end
379
+
380
+ def test_filter_parameters_using_array
381
+ filter_params_as_from_rails = [:password]
382
+ Raygun.configuration.filter_parameters = filter_params_as_from_rails
383
+
384
+ parameters = {
385
+ "something_normal" => "hello",
386
+ "password" => "wouldntyouliketoknow",
387
+ "password_confirmation" => "wouldntyouliketoknow",
388
+ "PasswORD_weird_case" => "anythingatall"
389
+ }
390
+
391
+ expected_form_hash = {
392
+ "something_normal" => "hello",
393
+ "password" => "[FILTERED]",
394
+ "password_confirmation" => "[FILTERED]",
395
+ "PasswORD_weird_case" => "[FILTERED]"
396
+ }
397
+
398
+ post_body_env_hash = sample_env_hash.merge(
399
+ "REQUEST_METHOD" => "POST",
400
+ "rack.input" => StringIO.new(URI.encode_www_form(parameters))
401
+ )
402
+
403
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
404
+ ensure
405
+ Raygun.configuration.filter_parameters = nil
406
+ end
407
+
408
+ def test_ip_address_from_action_dispatch
409
+ env_hash = sample_env_hash.merge({
410
+ "action_dispatch.remote_ip"=> "123.456.789.012"
411
+ })
412
+
413
+ assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
414
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
415
+ end
416
+
417
+ def test_ip_address_from_old_action_dispatch
418
+ old_action_dispatch_ip = FakeActionDispatcherIp.new("123.456.789.012")
419
+ env_hash = sample_env_hash.merge({
420
+ "action_dispatch.remote_ip"=> old_action_dispatch_ip
421
+ })
422
+
423
+ assert_equal old_action_dispatch_ip, @client.send(:ip_address_from, env_hash)
424
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
425
+ end
426
+
427
+ def test_ip_address_from_raygun_specific_key
428
+ env_hash = sample_env_hash.merge({
429
+ "raygun.remote_ip"=>"123.456.789.012"
430
+ })
431
+
432
+ assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
433
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
434
+ end
435
+
436
+ def test_ip_address_returns_not_available_if_not_set
437
+ env_hash = sample_env_hash.dup
438
+ env_hash.delete("REMOTE_ADDR")
439
+
440
+ assert_equal "(Not Available)", @client.send(:ip_address_from, env_hash)
441
+ end
442
+
443
+ def test_setting_up_http_proxy
444
+ begin
445
+ Raygun.configuration.proxy_settings[:address] = "http://proxy.com"
446
+ Raygun::Client.expects(:http_proxy).with("http://proxy.com", "80", nil, nil)
447
+
448
+ Raygun.track_exceptions do
449
+ raise TestException.new
450
+ end
451
+ ensure
452
+ Raygun.configuration.proxy_settings = {}
453
+ end
454
+ end
455
+
456
+ def test_filter_payload_with_whitelist_never_filters_toplevel
457
+ Timecop.freeze do
458
+ Raygun.configuration.filter_payload_with_whitelist = true
459
+ Raygun.configuration.whitelist_payload_shape = {}
460
+
461
+ e = test_exception
462
+
463
+ assert_equal Time.now.utc.iso8601, @client.send(:build_payload_hash, e)[:occurredOn]
464
+ assert_equal Hash, @client.send(:build_payload_hash, e)[:details].class
465
+ end
466
+ end
467
+
468
+ def test_filter_payload_with_whitelist_never_filters_client
469
+ Raygun.configuration.filter_payload_with_whitelist = true
470
+ Raygun.configuration.whitelist_payload_shape = {}
471
+
472
+ client_details = @client.send(:client_details)
473
+
474
+ assert_equal client_details, @client.send(:build_payload_hash, test_exception)[:details][:client]
475
+ end
476
+
477
+ def test_filter_payload_with_whitelist_default_error
478
+ Raygun.configuration.filter_payload_with_whitelist = true
479
+
480
+ details = @client.send(:build_payload_hash, test_exception)[:details]
481
+
482
+ assert_equal exception_hash, details[:error]
483
+ end
484
+
485
+ def test_filter_payload_with_whitelist_exclude_error_keys
486
+ Raygun.configuration.filter_payload_with_whitelist = true
487
+ Raygun.configuration.whitelist_payload_shape = {
488
+ error: {
489
+ className: true,
490
+ message: true,
491
+ stackTrace: true
492
+ }
493
+ }
494
+
495
+ details = @client.send(:build_payload_hash, test_exception)[:details]
496
+
497
+ assert_equal exception_hash, details[:error]
498
+ end
499
+
500
+ def test_filter_payload_with_whitelist_exclude_error_except_stacktrace
501
+ Raygun.configuration.filter_payload_with_whitelist = true
502
+ Raygun.configuration.whitelist_payload_shape = {
503
+ error: {
504
+ className: true,
505
+ message: true,
506
+ }
507
+ }
508
+
509
+ details = @client.send(:build_payload_hash, test_exception)[:details]
510
+
511
+ expected_hash = exception_hash.merge({
512
+ stackTrace: "[FILTERED]"
513
+ })
514
+
515
+ assert_equal expected_hash, details[:error]
516
+ end
517
+
518
+ def test_filter_payload_with_whitelist_proc
519
+ Raygun.configuration.filter_payload_with_whitelist = true
520
+ Raygun.configuration.whitelist_payload_shape do |payload|
521
+ payload
522
+ end
523
+
524
+ details = @client.send(:build_payload_hash, test_exception)[:details]
525
+
526
+ assert_equal exception_hash, details[:error]
527
+ end
528
+
529
+ def test_filter_payload_with_whitelist_default_request_post
530
+ Raygun.configuration.filter_payload_with_whitelist = true
531
+
532
+ post_body_env_hash = sample_env_hash.merge(
533
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
534
+ "REQUEST_METHOD" => "POST",
535
+ "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
536
+ )
537
+
538
+ details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
539
+
540
+ expected_hash = {
541
+ hostName: "localhost",
542
+ url: "/",
543
+ httpMethod: "POST",
544
+ iPAddress: "127.0.0.1",
545
+ queryString: { },
546
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
547
+ form: { "a" => "[FILTERED]", "c" => "[FILTERED]", "password" => "[FILTERED]" },
548
+ rawData: {}
549
+ }
550
+
551
+ assert_equal expected_hash, details[:request]
552
+ end
553
+
554
+ def test_filter_payload_with_whitelist_request_post_except_formkey
555
+ Raygun.configuration.filter_payload_with_whitelist = true
556
+ shape = Raygun.configuration.whitelist_payload_shape.dup
557
+ shape[:request] = Raygun.configuration.whitelist_payload_shape[:request].merge(
558
+ form: {
559
+ username: true
560
+ }
561
+ )
562
+ Raygun.configuration.whitelist_payload_shape = shape
563
+
564
+ post_body_env_hash = sample_env_hash.merge(
565
+ "REQUEST_METHOD" => "POST",
566
+ "rack.input"=>StringIO.new("username=foo&password=swordfish")
567
+ )
568
+
569
+ details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
570
+
571
+ expected_hash = {
572
+ hostName: "localhost",
573
+ url: "/",
574
+ httpMethod: "POST",
575
+ iPAddress: "127.0.0.1",
576
+ queryString: { },
577
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
578
+ form: { "username" => "foo", "password" => "[FILTERED]" },
579
+ rawData: {}
580
+ }
581
+
582
+ assert_equal expected_hash, details[:request]
583
+ end
584
+
585
+ def test_filter_payload_with_whitelist_default_request_get
586
+ Raygun.configuration.filter_payload_with_whitelist = true
587
+
588
+ env_hash = sample_env_hash.merge({
589
+ "QUERY_STRING"=>"a=b&c=4945438",
590
+ "REQUEST_URI"=>"/?a=b&c=4945438",
591
+ })
592
+ expected_hash = {
593
+ hostName: "localhost",
594
+ url: "/",
595
+ httpMethod: "GET",
596
+ iPAddress: "127.0.0.1",
597
+ queryString: { "a" => "b", "c" => "4945438" },
598
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
599
+ form: {},
600
+ rawData: nil
601
+ }
602
+
603
+ details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
604
+
605
+ assert_equal expected_hash, details[:request]
606
+ end
607
+
608
+ def test_filter_payload_with_whitelist_default_request_get_except_querystring
609
+ Raygun.configuration.filter_payload_with_whitelist = true
610
+ shape = Raygun.configuration.whitelist_payload_shape.dup
611
+ shape[:request] = Raygun::Configuration::DEFAULT_WHITELIST_PAYLOAD_SHAPE_REQUEST.dup.tap do |h|
612
+ h.delete(:queryString)
613
+ end
614
+ Raygun.configuration.whitelist_payload_shape = shape
615
+
616
+ expected_hash = {
617
+ hostName: "localhost",
618
+ url: "/",
619
+ httpMethod: "GET",
620
+ iPAddress: "127.0.0.1",
621
+ queryString: "[FILTERED]",
622
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
623
+ form: {},
624
+ rawData: nil
625
+ }
626
+
627
+ details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
628
+
629
+ assert_equal expected_hash, details[:request]
630
+ end
631
+
632
+ def test_filter_payload_with_whitelist_being_false_does_not_filter_query_string
633
+ Raygun.configuration.filter_payload_with_whitelist = false
634
+
635
+ env_hash = sample_env_hash.merge({
636
+ "QUERY_STRING"=>"a=b&c=4945438",
637
+ "REQUEST_URI"=>"/?a=b&c=4945438",
638
+ })
639
+ expected_hash = {
640
+ hostName: "localhost",
641
+ url: "/",
642
+ httpMethod: "GET",
643
+ iPAddress: "127.0.0.1",
644
+ queryString: { "a" => "b", "c" => "4945438" },
645
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
646
+ form: {},
647
+ rawData: nil
648
+ }
649
+
650
+ details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
651
+
652
+ assert_equal expected_hash, details[:request]
653
+ end
654
+
655
+ def test_filter_payload_with_whitelist_request_specific_keys
656
+ Raygun.configuration.filter_payload_with_whitelist = true
657
+ Raygun.configuration.whitelist_payload_shape = {
658
+ request: {
659
+ url: true,
660
+ httpMethod: true,
661
+ hostName: true
662
+ }
663
+ }
664
+
665
+ details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
666
+
667
+ expected_hash = {
668
+ hostName: "localhost",
669
+ url: "/",
670
+ httpMethod: "GET",
671
+ iPAddress: "[FILTERED]",
672
+ queryString: "[FILTERED]",
673
+ headers: "[FILTERED]",
674
+ form: "[FILTERED]",
675
+ rawData: "[FILTERED]"
676
+ }
677
+
678
+ assert_equal expected_hash, details[:request]
679
+ end
680
+
681
+
682
+ def test_filter_payload_with_whitelist_and_filter_parameters_applies_both
683
+ Raygun.configuration.filter_parameters = [:password]
684
+ Raygun.configuration.filter_payload_with_whitelist = true
685
+ Raygun.configuration.whitelist_payload_shape = proc do |payload|
686
+ payload[:request][:headers]["Cookie"] = "[FILTERED]"
687
+ payload
688
+ end
689
+
690
+ parameters = {
691
+ "something_normal" => "hello",
692
+ "password" => "wouldntyouliketoknow"
693
+ }
694
+
695
+ post_body_env_hash = sample_env_hash.merge(
696
+ "REQUEST_METHOD" => "POST",
697
+ "rack.input" => StringIO.new(URI.encode_www_form(parameters))
698
+ )
699
+
700
+ payload = @client.send(:build_payload_hash, test_exception, post_body_env_hash)
701
+ request_payload = payload[:details][:request]
702
+
703
+ expected_form = {
704
+ "something_normal" => "hello",
705
+ "password" => "[FILTERED]"
706
+ }
707
+
708
+ assert_equal expected_form, request_payload[:form]
709
+
710
+ expected_headers = {
711
+ "Version" => "HTTP/1.1",
712
+ "Host" => "localhost:3000",
713
+ "Cookie" => "[FILTERED]"
714
+ }
715
+
716
+ assert_equal expected_headers, request_payload[:headers]
717
+ end
718
+
719
+ def test_build_payload_hash_adds_affected_user_details_when_supplied_with_user
720
+ user = OpenStruct.new(id: '123', email: 'test@email.com', first_name: 'Taylor')
721
+ expected_details = {
722
+ :isAnonymous => false,
723
+ :identifier => '123',
724
+ :email => 'test@email.com',
725
+ :firstName => 'Taylor',
726
+ }
727
+
728
+ user_details = @client.send(:build_payload_hash, test_exception, sample_env_hash, user)[:details][:user]
729
+
730
+ assert_equal expected_details, user_details
731
+ end
732
+
733
+ def test_build_payload_includes_breadcrumbs
734
+ ::Raygun::Breadcrumbs::Store.initialize
735
+ ::Raygun::Breadcrumbs::Store.record(message: "foo")
736
+
737
+ breadcrumbs = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:breadcrumbs]
738
+ ::Raygun::Breadcrumbs::Store.clear
739
+
740
+ assert_equal breadcrumbs.length, 1
741
+ assert breadcrumbs[0].is_a? Hash
742
+ end
743
+
744
+ def test_raw_data_does_not_crash_on_buffer_without_pos
745
+ buffer = StringIO.new('123456789')
746
+ rack_env = {
747
+ REQUEST_METHOD: 'POST',
748
+ 'rack.input' => buffer
749
+ }
750
+
751
+ buffer.instance_eval('undef :pos')
752
+
753
+ raw_data = @client.send(:raw_data, rack_env)
754
+
755
+ assert_equal('123456789', raw_data)
756
+ end
757
+
758
+ private
759
+
760
+ def test_exception
761
+ e = TestException.new
762
+ e.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'",
763
+ "/another/path/foo.rb:1234:in `block (3 levels) run'"])
764
+
765
+ e
766
+ end
767
+
768
+ def nest_exceptions(outer_exception, inner_exception)
769
+ begin
770
+ begin
771
+ raise inner_exception.class, inner_exception.message
772
+ rescue => e
773
+ e.set_backtrace inner_exception.backtrace
774
+ raise outer_exception.class, outer_exception.message
775
+ end
776
+ rescue => nested_exception
777
+ nested_exception.set_backtrace outer_exception.backtrace
778
+ end
779
+
780
+ nested_exception
781
+ end
782
+
783
+ def exception_hash
784
+ {
785
+ className: "ClientTest::TestException",
786
+ message: "A test message",
787
+ stackTrace: [
788
+ { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" },
789
+ { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
790
+ ]
791
+ }
792
+ end
793
+
794
+ def sample_env_hash
795
+ {
796
+ "SERVER_NAME"=>"localhost",
797
+ "REQUEST_METHOD"=>"GET",
798
+ "REQUEST_PATH"=>"/",
799
+ "PATH_INFO"=>"/",
800
+ "QUERY_STRING"=>"",
801
+ "REQUEST_URI"=>"/",
802
+ "HTTP_VERSION"=>"HTTP/1.1",
803
+ "HTTP_HOST"=>"localhost:3000",
804
+ "HTTP_COOKIE"=>"cookieval",
805
+ "GATEWAY_INTERFACE"=>"CGI/1.2",
806
+ "SERVER_PORT"=>"3000",
807
+ "SERVER_PROTOCOL"=>"HTTP/1.1",
808
+ "SCRIPT_NAME"=>"",
809
+ "REMOTE_ADDR"=>"127.0.0.1"
810
+ }
811
+ end
812
+ end