raygun4ruby 3.2.3 → 3.2.4

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -18
  3. data/.rspec +1 -1
  4. data/.travis.yml +20 -20
  5. data/CHANGELOG.md +127 -124
  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 +305 -305
  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 -70
  28. data/lib/raygun/testable.rb +22 -22
  29. data/lib/raygun/version.rb +3 -3
  30. data/lib/raygun4ruby.rb +1 -1
  31. data/lib/resque/failure/raygun.rb +25 -25
  32. data/lib/tasks/raygun.tasks +7 -7
  33. data/raygun4ruby.gemspec +45 -45
  34. data/spec/dummy/.gitignore +17 -17
  35. data/spec/dummy/Gemfile +47 -47
  36. data/spec/dummy/README.rdoc +28 -28
  37. data/spec/dummy/Rakefile +6 -6
  38. data/spec/dummy/app/assets/config/manifest.js +2 -2
  39. data/spec/dummy/app/assets/javascripts/application.js +13 -13
  40. data/spec/dummy/app/assets/stylesheets/application.css +15 -15
  41. data/spec/dummy/app/controllers/application_controller.rb +5 -5
  42. data/spec/dummy/app/controllers/home_controller.rb +4 -4
  43. data/spec/dummy/app/helpers/application_helper.rb +2 -2
  44. data/spec/dummy/app/views/home/index.html.erb +3 -3
  45. data/spec/dummy/app/views/home/index.json.erb +1 -1
  46. data/spec/dummy/app/views/layouts/application.html.erb +14 -14
  47. data/spec/dummy/bin/bundle +3 -3
  48. data/spec/dummy/bin/rails +9 -9
  49. data/spec/dummy/bin/rake +9 -9
  50. data/spec/dummy/bin/setup +29 -29
  51. data/spec/dummy/bin/spring +17 -17
  52. data/spec/dummy/config.ru +4 -4
  53. data/spec/dummy/config/application.rb +26 -26
  54. data/spec/dummy/config/boot.rb +3 -3
  55. data/spec/dummy/config/database.yml +25 -25
  56. data/spec/dummy/config/environment.rb +5 -5
  57. data/spec/dummy/config/environments/development.rb +41 -41
  58. data/spec/dummy/config/environments/production.rb +79 -79
  59. data/spec/dummy/config/environments/test.rb +42 -42
  60. data/spec/dummy/config/initializers/assets.rb +11 -11
  61. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
  62. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -3
  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 -3
  67. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -10
  68. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  69. data/spec/dummy/config/locales/en.yml +23 -23
  70. data/spec/dummy/config/routes.rb +58 -58
  71. data/spec/dummy/config/secrets.yml +22 -22
  72. data/spec/dummy/db/seeds.rb +7 -7
  73. data/spec/dummy/public/404.html +67 -67
  74. data/spec/dummy/public/422.html +67 -67
  75. data/spec/dummy/public/500.html +66 -66
  76. data/spec/dummy/public/robots.txt +5 -5
  77. data/spec/dummy/test/test_helper.rb +10 -10
  78. data/spec/features/javascript_spec.rb +48 -48
  79. data/spec/rails_helper.rb +4 -4
  80. data/spec/raygun/breadcrumbs/breadcrumb_spec.rb +171 -171
  81. data/spec/raygun/breadcrumbs/store_spec.rb +170 -170
  82. data/spec/raygun/raygun_spec.rb +47 -47
  83. data/spec/services/apply_whitelist_filter_to_payload_spec.rb +251 -251
  84. data/spec/spec_helper.rb +24 -24
  85. data/spec/support/fake_logger.rb +17 -17
  86. data/test/integration/client_test.rb +19 -19
  87. data/test/test_helper.rb +72 -72
  88. data/test/unit/affected_user_test.rb +136 -136
  89. data/test/unit/client_test.rb +792 -792
  90. data/test/unit/configuration_test.rb +206 -206
  91. data/test/unit/raygun_test.rb +25 -25
  92. data/test/unit/resque_failure_test.rb +24 -24
  93. data/test/unit/sidekiq_failure_test.rb +32 -32
  94. metadata +7 -7
@@ -1,792 +1,792 @@
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
- correlation_id = "my correlation id"
202
-
203
- expected_hash = {
204
- occurredOn: Time.now.utc.iso8601,
205
- details: {
206
- machineName: Socket.gethostname,
207
- version: 123,
208
- client: {
209
- name: Raygun::CLIENT_NAME,
210
- version: Raygun::VERSION,
211
- clientUrl: Raygun::CLIENT_URL
212
- },
213
- error: exception_hash,
214
- userCustomData: {},
215
- tags: ["test"],
216
- request: {},
217
- groupingKey: grouping_key,
218
- correlationId: correlation_id,
219
- environment: {
220
- utcOffset: 13
221
- }
222
- }
223
- }
224
-
225
- assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, { grouping_key: grouping_key, correlation_id: correlation_id })
226
- end
227
- end
228
-
229
- def test_getting_request_information
230
- env_hash = sample_env_hash.merge({
231
- "QUERY_STRING"=>"a=b&c=4945438",
232
- "REQUEST_URI"=>"/?a=b&c=4945438",
233
- })
234
-
235
- expected_hash = {
236
- hostName: "localhost",
237
- url: "/",
238
- httpMethod: "GET",
239
- iPAddress: "127.0.0.1",
240
- queryString: { "a" => "b", "c" => "4945438" },
241
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
242
- form: {},
243
- rawData: nil
244
- }
245
-
246
- assert_equal expected_hash, @client.send(:request_information, env_hash)
247
- end
248
-
249
- def test_getting_request_information_with_nil_env
250
- assert_equal({}, @client.send(:request_information, nil))
251
- end
252
-
253
- def test_raw_post_body
254
- env_hash = sample_env_hash.merge({
255
- "CONTENT_TYPE" => "application/json",
256
- "REQUEST_METHOD" => "POST",
257
- "rack.input" => StringIO.new('{"foo": "bar"}')
258
- })
259
-
260
- assert_equal '{"foo": "bar"}', @client.send(:request_information, env_hash)[:rawData]
261
- end
262
-
263
- def test_raw_post_body_with_more_than_4096_chars
264
- input = "0" * 5000;
265
- env_hash = sample_env_hash.merge({
266
- "CONTENT_TYPE" => "application/json",
267
- "REQUEST_METHOD" => "POST",
268
- "rack.input" => StringIO.new(input)
269
- })
270
-
271
- assert_equal input.slice(0, 4096), @client.send(:request_information, env_hash)[:rawData]
272
- end
273
-
274
- def test_raw_post_body_with_config_disabled
275
- Raygun.configuration.record_raw_data = false
276
- env_hash = sample_env_hash.merge({
277
- "CONTENT_TYPE" => "application/json",
278
- "REQUEST_METHOD" => "POST",
279
- "rack.input" => StringIO.new('{"foo": "bar"}')
280
- })
281
-
282
- assert_equal(nil, @client.send(:request_information, env_hash)[:rawData])
283
- end
284
-
285
- def test_error_raygun_custom_data
286
- custom_data = { "kappa" => "keepo" }
287
- e = Raygun::Error.new("A test message", custom_data)
288
- test_env = {}
289
- expected_form_hash = test_env.merge(custom_data)
290
-
291
- assert_equal expected_form_hash, @client.send(:build_payload_hash, e, test_env)[:details][:userCustomData]
292
- end
293
-
294
- def test_custom_data_configuration_with_hash
295
- custom_data = {foo: '123'}
296
- Raygun.configuration.custom_data = custom_data
297
-
298
- assert_equal custom_data, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
299
- end
300
-
301
- def test_custom_data_configuration_with_proc
302
- Raygun.configuration.custom_data do |exception, env|
303
- {exception_message: exception.message, server_name: env["SERVER_NAME"]}
304
- end
305
- expected = {
306
- exception_message: "A test message",
307
- server_name: "localhost"
308
- }
309
-
310
- assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
311
- end
312
-
313
- def test_filtering_parameters
314
- post_body_env_hash = sample_env_hash.merge(
315
- "REQUEST_METHOD" => "POST",
316
- "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
317
- )
318
-
319
- expected_form_hash = { "a" => "b", "c" => "4945438", "password" => "[FILTERED]" }
320
-
321
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
322
- end
323
-
324
- def test_filtering_nested_params
325
- post_body_env_hash = sample_env_hash.merge(
326
- "REQUEST_METHOD" => "POST",
327
- "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")
328
- )
329
-
330
- expected_form_hash = { "a" => "b", "bank" => { "credit_card" => { "card_number" => "[FILTERED]" }, "name" => "something" }, "c" => "123456", "user" => { "password" => "[FILTERED]" } }
331
-
332
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
333
- end
334
-
335
- def test_filter_parameters_using_proc
336
- # filter any parameters that start with "nsa_only"
337
- Raygun.configuration.filter_parameters do |hash|
338
- hash.inject({}) do |sanitized_hash, (k, v)|
339
- sanitized_hash[k] = if k.start_with? "nsa_only"
340
- "[OUREYESONLY]"
341
- else
342
- v
343
- end
344
- sanitized_hash
345
- end
346
- end
347
-
348
- post_body_env_hash = sample_env_hash.merge(
349
- "REQUEST_METHOD" => "POST",
350
- "rack.input" => StringIO.new("nsa_only_info=123&nsa_only_metadata=seekrit&something_normal=hello")
351
- )
352
-
353
- expected_form_hash = { "nsa_only_info" => "[OUREYESONLY]", "nsa_only_metadata" => "[OUREYESONLY]", "something_normal" => "hello" }
354
-
355
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
356
- ensure
357
- Raygun.configuration.filter_parameters = nil
358
- end
359
-
360
- def test_filter_parameters_using_array
361
- filter_params_as_from_rails = [:password]
362
- Raygun.configuration.filter_parameters = filter_params_as_from_rails
363
-
364
- parameters = {
365
- "something_normal" => "hello",
366
- "password" => "wouldntyouliketoknow",
367
- "password_confirmation" => "wouldntyouliketoknow",
368
- "PasswORD_weird_case" => "anythingatall"
369
- }
370
-
371
- expected_form_hash = {
372
- "something_normal" => "hello",
373
- "password" => "[FILTERED]",
374
- "password_confirmation" => "[FILTERED]",
375
- "PasswORD_weird_case" => "[FILTERED]"
376
- }
377
-
378
- post_body_env_hash = sample_env_hash.merge(
379
- "REQUEST_METHOD" => "POST",
380
- "rack.input" => StringIO.new(URI.encode_www_form(parameters))
381
- )
382
-
383
- assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
384
- ensure
385
- Raygun.configuration.filter_parameters = nil
386
- end
387
-
388
- def test_ip_address_from_action_dispatch
389
- env_hash = sample_env_hash.merge({
390
- "action_dispatch.remote_ip"=> "123.456.789.012"
391
- })
392
-
393
- assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
394
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
395
- end
396
-
397
- def test_ip_address_from_old_action_dispatch
398
- old_action_dispatch_ip = FakeActionDispatcherIp.new("123.456.789.012")
399
- env_hash = sample_env_hash.merge({
400
- "action_dispatch.remote_ip"=> old_action_dispatch_ip
401
- })
402
-
403
- assert_equal old_action_dispatch_ip, @client.send(:ip_address_from, env_hash)
404
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
405
- end
406
-
407
- def test_ip_address_from_raygun_specific_key
408
- env_hash = sample_env_hash.merge({
409
- "raygun.remote_ip"=>"123.456.789.012"
410
- })
411
-
412
- assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
413
- assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
414
- end
415
-
416
- def test_ip_address_returns_not_available_if_not_set
417
- env_hash = sample_env_hash.dup
418
- env_hash.delete("REMOTE_ADDR")
419
-
420
- assert_equal "(Not Available)", @client.send(:ip_address_from, env_hash)
421
- end
422
-
423
- def test_setting_up_http_proxy
424
- begin
425
- Raygun.configuration.proxy_settings[:address] = "http://proxy.com"
426
- Raygun::Client.expects(:http_proxy).with("http://proxy.com", "80", nil, nil)
427
-
428
- Raygun.track_exceptions do
429
- raise TestException.new
430
- end
431
- ensure
432
- Raygun.configuration.proxy_settings = {}
433
- end
434
- end
435
-
436
- def test_filter_payload_with_whitelist_never_filters_toplevel
437
- Timecop.freeze do
438
- Raygun.configuration.filter_payload_with_whitelist = true
439
- Raygun.configuration.whitelist_payload_shape = {}
440
-
441
- e = test_exception
442
-
443
- assert_equal Time.now.utc.iso8601, @client.send(:build_payload_hash, e)[:occurredOn]
444
- assert_equal Hash, @client.send(:build_payload_hash, e)[:details].class
445
- end
446
- end
447
-
448
- def test_filter_payload_with_whitelist_never_filters_client
449
- Raygun.configuration.filter_payload_with_whitelist = true
450
- Raygun.configuration.whitelist_payload_shape = {}
451
-
452
- client_details = @client.send(:client_details)
453
-
454
- assert_equal client_details, @client.send(:build_payload_hash, test_exception)[:details][:client]
455
- end
456
-
457
- def test_filter_payload_with_whitelist_default_error
458
- Raygun.configuration.filter_payload_with_whitelist = true
459
-
460
- details = @client.send(:build_payload_hash, test_exception)[:details]
461
-
462
- assert_equal exception_hash, details[:error]
463
- end
464
-
465
- def test_filter_payload_with_whitelist_exclude_error_keys
466
- Raygun.configuration.filter_payload_with_whitelist = true
467
- Raygun.configuration.whitelist_payload_shape = {
468
- error: {
469
- className: true,
470
- message: true,
471
- stackTrace: true
472
- }
473
- }
474
-
475
- details = @client.send(:build_payload_hash, test_exception)[:details]
476
-
477
- assert_equal exception_hash, details[:error]
478
- end
479
-
480
- def test_filter_payload_with_whitelist_exclude_error_except_stacktrace
481
- Raygun.configuration.filter_payload_with_whitelist = true
482
- Raygun.configuration.whitelist_payload_shape = {
483
- error: {
484
- className: true,
485
- message: true,
486
- }
487
- }
488
-
489
- details = @client.send(:build_payload_hash, test_exception)[:details]
490
-
491
- expected_hash = exception_hash.merge({
492
- stackTrace: "[FILTERED]"
493
- })
494
-
495
- assert_equal expected_hash, details[:error]
496
- end
497
-
498
- def test_filter_payload_with_whitelist_proc
499
- Raygun.configuration.filter_payload_with_whitelist = true
500
- Raygun.configuration.whitelist_payload_shape do |payload|
501
- payload
502
- end
503
-
504
- details = @client.send(:build_payload_hash, test_exception)[:details]
505
-
506
- assert_equal exception_hash, details[:error]
507
- end
508
-
509
- def test_filter_payload_with_whitelist_default_request_post
510
- Raygun.configuration.filter_payload_with_whitelist = true
511
-
512
- post_body_env_hash = sample_env_hash.merge(
513
- "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
514
- "REQUEST_METHOD" => "POST",
515
- "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
516
- )
517
-
518
- details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
519
-
520
- expected_hash = {
521
- hostName: "localhost",
522
- url: "/",
523
- httpMethod: "POST",
524
- iPAddress: "127.0.0.1",
525
- queryString: { },
526
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
527
- form: { "a" => "[FILTERED]", "c" => "[FILTERED]", "password" => "[FILTERED]" },
528
- rawData: {}
529
- }
530
-
531
- assert_equal expected_hash, details[:request]
532
- end
533
-
534
- def test_filter_payload_with_whitelist_request_post_except_formkey
535
- Raygun.configuration.filter_payload_with_whitelist = true
536
- shape = Raygun.configuration.whitelist_payload_shape.dup
537
- shape[:request] = Raygun.configuration.whitelist_payload_shape[:request].merge(
538
- form: {
539
- username: true
540
- }
541
- )
542
- Raygun.configuration.whitelist_payload_shape = shape
543
-
544
- post_body_env_hash = sample_env_hash.merge(
545
- "REQUEST_METHOD" => "POST",
546
- "rack.input"=>StringIO.new("username=foo&password=swordfish")
547
- )
548
-
549
- details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
550
-
551
- expected_hash = {
552
- hostName: "localhost",
553
- url: "/",
554
- httpMethod: "POST",
555
- iPAddress: "127.0.0.1",
556
- queryString: { },
557
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
558
- form: { "username" => "foo", "password" => "[FILTERED]" },
559
- rawData: {}
560
- }
561
-
562
- assert_equal expected_hash, details[:request]
563
- end
564
-
565
- def test_filter_payload_with_whitelist_default_request_get
566
- Raygun.configuration.filter_payload_with_whitelist = true
567
-
568
- env_hash = sample_env_hash.merge({
569
- "QUERY_STRING"=>"a=b&c=4945438",
570
- "REQUEST_URI"=>"/?a=b&c=4945438",
571
- })
572
- expected_hash = {
573
- hostName: "localhost",
574
- url: "/",
575
- httpMethod: "GET",
576
- iPAddress: "127.0.0.1",
577
- queryString: { "a" => "b", "c" => "4945438" },
578
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
579
- form: {},
580
- rawData: nil
581
- }
582
-
583
- details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
584
-
585
- assert_equal expected_hash, details[:request]
586
- end
587
-
588
- def test_filter_payload_with_whitelist_default_request_get_except_querystring
589
- Raygun.configuration.filter_payload_with_whitelist = true
590
- shape = Raygun.configuration.whitelist_payload_shape.dup
591
- shape[:request] = Raygun::Configuration::DEFAULT_WHITELIST_PAYLOAD_SHAPE_REQUEST.dup.tap do |h|
592
- h.delete(:queryString)
593
- end
594
- Raygun.configuration.whitelist_payload_shape = shape
595
-
596
- expected_hash = {
597
- hostName: "localhost",
598
- url: "/",
599
- httpMethod: "GET",
600
- iPAddress: "127.0.0.1",
601
- queryString: "[FILTERED]",
602
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
603
- form: {},
604
- rawData: nil
605
- }
606
-
607
- details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
608
-
609
- assert_equal expected_hash, details[:request]
610
- end
611
-
612
- def test_filter_payload_with_whitelist_being_false_does_not_filter_query_string
613
- Raygun.configuration.filter_payload_with_whitelist = false
614
-
615
- env_hash = sample_env_hash.merge({
616
- "QUERY_STRING"=>"a=b&c=4945438",
617
- "REQUEST_URI"=>"/?a=b&c=4945438",
618
- })
619
- expected_hash = {
620
- hostName: "localhost",
621
- url: "/",
622
- httpMethod: "GET",
623
- iPAddress: "127.0.0.1",
624
- queryString: { "a" => "b", "c" => "4945438" },
625
- headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
626
- form: {},
627
- rawData: nil
628
- }
629
-
630
- details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
631
-
632
- assert_equal expected_hash, details[:request]
633
- end
634
-
635
- def test_filter_payload_with_whitelist_request_specific_keys
636
- Raygun.configuration.filter_payload_with_whitelist = true
637
- Raygun.configuration.whitelist_payload_shape = {
638
- request: {
639
- url: true,
640
- httpMethod: true,
641
- hostName: true
642
- }
643
- }
644
-
645
- details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
646
-
647
- expected_hash = {
648
- hostName: "localhost",
649
- url: "/",
650
- httpMethod: "GET",
651
- iPAddress: "[FILTERED]",
652
- queryString: "[FILTERED]",
653
- headers: "[FILTERED]",
654
- form: "[FILTERED]",
655
- rawData: "[FILTERED]"
656
- }
657
-
658
- assert_equal expected_hash, details[:request]
659
- end
660
-
661
-
662
- def test_filter_payload_with_whitelist_and_filter_parameters_applies_both
663
- Raygun.configuration.filter_parameters = [:password]
664
- Raygun.configuration.filter_payload_with_whitelist = true
665
- Raygun.configuration.whitelist_payload_shape = proc do |payload|
666
- payload[:request][:headers]["Cookie"] = "[FILTERED]"
667
- payload
668
- end
669
-
670
- parameters = {
671
- "something_normal" => "hello",
672
- "password" => "wouldntyouliketoknow"
673
- }
674
-
675
- post_body_env_hash = sample_env_hash.merge(
676
- "REQUEST_METHOD" => "POST",
677
- "rack.input" => StringIO.new(URI.encode_www_form(parameters))
678
- )
679
-
680
- payload = @client.send(:build_payload_hash, test_exception, post_body_env_hash)
681
- request_payload = payload[:details][:request]
682
-
683
- expected_form = {
684
- "something_normal" => "hello",
685
- "password" => "[FILTERED]"
686
- }
687
-
688
- assert_equal expected_form, request_payload[:form]
689
-
690
- expected_headers = {
691
- "Version" => "HTTP/1.1",
692
- "Host" => "localhost:3000",
693
- "Cookie" => "[FILTERED]"
694
- }
695
-
696
- assert_equal expected_headers, request_payload[:headers]
697
- end
698
-
699
- def test_build_payload_hash_adds_affected_user_details_when_supplied_with_user
700
- user = OpenStruct.new(id: '123', email: 'test@email.com', first_name: 'Taylor')
701
- expected_details = {
702
- :isAnonymous => false,
703
- :identifier => '123',
704
- :email => 'test@email.com',
705
- :firstName => 'Taylor',
706
- }
707
-
708
- user_details = @client.send(:build_payload_hash, test_exception, sample_env_hash, user)[:details][:user]
709
-
710
- assert_equal expected_details, user_details
711
- end
712
-
713
- def test_build_payload_includes_breadcrumbs
714
- ::Raygun::Breadcrumbs::Store.initialize
715
- ::Raygun::Breadcrumbs::Store.record(message: "foo")
716
-
717
- breadcrumbs = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:breadcrumbs]
718
- ::Raygun::Breadcrumbs::Store.clear
719
-
720
- assert_equal breadcrumbs.length, 1
721
- assert breadcrumbs[0].is_a? Hash
722
- end
723
-
724
- def test_raw_data_does_not_crash_on_buffer_without_pos
725
- buffer = StringIO.new('123456789')
726
- rack_env = {
727
- REQUEST_METHOD: 'POST',
728
- 'rack.input' => buffer
729
- }
730
-
731
- buffer.instance_eval('undef :pos')
732
-
733
- raw_data = @client.send(:raw_data, rack_env)
734
-
735
- assert_equal('123456789', raw_data)
736
- end
737
-
738
- private
739
-
740
- def test_exception
741
- e = TestException.new
742
- e.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'",
743
- "/another/path/foo.rb:1234:in `block (3 levels) run'"])
744
-
745
- e
746
- end
747
-
748
- def nest_exceptions(outer_exception, inner_exception)
749
- begin
750
- begin
751
- raise inner_exception.class, inner_exception.message
752
- rescue => e
753
- e.set_backtrace inner_exception.backtrace
754
- raise outer_exception.class, outer_exception.message
755
- end
756
- rescue => nested_exception
757
- nested_exception.set_backtrace outer_exception.backtrace
758
- end
759
-
760
- nested_exception
761
- end
762
-
763
- def exception_hash
764
- {
765
- className: "ClientTest::TestException",
766
- message: "A test message",
767
- stackTrace: [
768
- { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" },
769
- { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
770
- ]
771
- }
772
- end
773
-
774
- def sample_env_hash
775
- {
776
- "SERVER_NAME"=>"localhost",
777
- "REQUEST_METHOD"=>"GET",
778
- "REQUEST_PATH"=>"/",
779
- "PATH_INFO"=>"/",
780
- "QUERY_STRING"=>"",
781
- "REQUEST_URI"=>"/",
782
- "HTTP_VERSION"=>"HTTP/1.1",
783
- "HTTP_HOST"=>"localhost:3000",
784
- "HTTP_COOKIE"=>"cookieval",
785
- "GATEWAY_INTERFACE"=>"CGI/1.2",
786
- "SERVER_PORT"=>"3000",
787
- "SERVER_PROTOCOL"=>"HTTP/1.1",
788
- "SCRIPT_NAME"=>"",
789
- "REMOTE_ADDR"=>"127.0.0.1"
790
- }
791
- end
792
- 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_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
+ correlation_id = "my correlation id"
202
+
203
+ expected_hash = {
204
+ occurredOn: Time.now.utc.iso8601,
205
+ details: {
206
+ machineName: Socket.gethostname,
207
+ version: 123,
208
+ client: {
209
+ name: Raygun::CLIENT_NAME,
210
+ version: Raygun::VERSION,
211
+ clientUrl: Raygun::CLIENT_URL
212
+ },
213
+ error: exception_hash,
214
+ userCustomData: {},
215
+ tags: ["test"],
216
+ request: {},
217
+ groupingKey: grouping_key,
218
+ correlationId: correlation_id,
219
+ environment: {
220
+ utcOffset: 13
221
+ }
222
+ }
223
+ }
224
+
225
+ assert_equal expected_hash, @client.send(:build_payload_hash, test_exception, { grouping_key: grouping_key, correlation_id: correlation_id })
226
+ end
227
+ end
228
+
229
+ def test_getting_request_information
230
+ env_hash = sample_env_hash.merge({
231
+ "QUERY_STRING"=>"a=b&c=4945438",
232
+ "REQUEST_URI"=>"/?a=b&c=4945438",
233
+ })
234
+
235
+ expected_hash = {
236
+ hostName: "localhost",
237
+ url: "/",
238
+ httpMethod: "GET",
239
+ iPAddress: "127.0.0.1",
240
+ queryString: { "a" => "b", "c" => "4945438" },
241
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
242
+ form: {},
243
+ rawData: nil
244
+ }
245
+
246
+ assert_equal expected_hash, @client.send(:request_information, env_hash)
247
+ end
248
+
249
+ def test_getting_request_information_with_nil_env
250
+ assert_equal({}, @client.send(:request_information, nil))
251
+ end
252
+
253
+ def test_raw_post_body
254
+ env_hash = sample_env_hash.merge({
255
+ "CONTENT_TYPE" => "application/json",
256
+ "REQUEST_METHOD" => "POST",
257
+ "rack.input" => StringIO.new('{"foo": "bar"}')
258
+ })
259
+
260
+ assert_equal '{"foo": "bar"}', @client.send(:request_information, env_hash)[:rawData]
261
+ end
262
+
263
+ def test_raw_post_body_with_more_than_4096_chars
264
+ input = "0" * 5000;
265
+ env_hash = sample_env_hash.merge({
266
+ "CONTENT_TYPE" => "application/json",
267
+ "REQUEST_METHOD" => "POST",
268
+ "rack.input" => StringIO.new(input)
269
+ })
270
+
271
+ assert_equal input.slice(0, 4096), @client.send(:request_information, env_hash)[:rawData]
272
+ end
273
+
274
+ def test_raw_post_body_with_config_disabled
275
+ Raygun.configuration.record_raw_data = false
276
+ env_hash = sample_env_hash.merge({
277
+ "CONTENT_TYPE" => "application/json",
278
+ "REQUEST_METHOD" => "POST",
279
+ "rack.input" => StringIO.new('{"foo": "bar"}')
280
+ })
281
+
282
+ assert_equal(nil, @client.send(:request_information, env_hash)[:rawData])
283
+ end
284
+
285
+ def test_error_raygun_custom_data
286
+ custom_data = { "kappa" => "keepo" }
287
+ e = Raygun::Error.new("A test message", custom_data)
288
+ test_env = {}
289
+ expected_form_hash = test_env.merge(custom_data)
290
+
291
+ assert_equal expected_form_hash, @client.send(:build_payload_hash, e, test_env)[:details][:userCustomData]
292
+ end
293
+
294
+ def test_custom_data_configuration_with_hash
295
+ custom_data = {foo: '123'}
296
+ Raygun.configuration.custom_data = custom_data
297
+
298
+ assert_equal custom_data, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
299
+ end
300
+
301
+ def test_custom_data_configuration_with_proc
302
+ Raygun.configuration.custom_data do |exception, env|
303
+ {exception_message: exception.message, server_name: env["SERVER_NAME"]}
304
+ end
305
+ expected = {
306
+ exception_message: "A test message",
307
+ server_name: "localhost"
308
+ }
309
+
310
+ assert_equal expected, @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:userCustomData]
311
+ end
312
+
313
+ def test_filtering_parameters
314
+ post_body_env_hash = sample_env_hash.merge(
315
+ "REQUEST_METHOD" => "POST",
316
+ "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
317
+ )
318
+
319
+ expected_form_hash = { "a" => "b", "c" => "4945438", "password" => "[FILTERED]" }
320
+
321
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
322
+ end
323
+
324
+ def test_filtering_nested_params
325
+ post_body_env_hash = sample_env_hash.merge(
326
+ "REQUEST_METHOD" => "POST",
327
+ "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")
328
+ )
329
+
330
+ expected_form_hash = { "a" => "b", "bank" => { "credit_card" => { "card_number" => "[FILTERED]" }, "name" => "something" }, "c" => "123456", "user" => { "password" => "[FILTERED]" } }
331
+
332
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
333
+ end
334
+
335
+ def test_filter_parameters_using_proc
336
+ # filter any parameters that start with "nsa_only"
337
+ Raygun.configuration.filter_parameters do |hash|
338
+ hash.inject({}) do |sanitized_hash, (k, v)|
339
+ sanitized_hash[k] = if k.start_with? "nsa_only"
340
+ "[OUREYESONLY]"
341
+ else
342
+ v
343
+ end
344
+ sanitized_hash
345
+ end
346
+ end
347
+
348
+ post_body_env_hash = sample_env_hash.merge(
349
+ "REQUEST_METHOD" => "POST",
350
+ "rack.input" => StringIO.new("nsa_only_info=123&nsa_only_metadata=seekrit&something_normal=hello")
351
+ )
352
+
353
+ expected_form_hash = { "nsa_only_info" => "[OUREYESONLY]", "nsa_only_metadata" => "[OUREYESONLY]", "something_normal" => "hello" }
354
+
355
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
356
+ ensure
357
+ Raygun.configuration.filter_parameters = nil
358
+ end
359
+
360
+ def test_filter_parameters_using_array
361
+ filter_params_as_from_rails = [:password]
362
+ Raygun.configuration.filter_parameters = filter_params_as_from_rails
363
+
364
+ parameters = {
365
+ "something_normal" => "hello",
366
+ "password" => "wouldntyouliketoknow",
367
+ "password_confirmation" => "wouldntyouliketoknow",
368
+ "PasswORD_weird_case" => "anythingatall"
369
+ }
370
+
371
+ expected_form_hash = {
372
+ "something_normal" => "hello",
373
+ "password" => "[FILTERED]",
374
+ "password_confirmation" => "[FILTERED]",
375
+ "PasswORD_weird_case" => "[FILTERED]"
376
+ }
377
+
378
+ post_body_env_hash = sample_env_hash.merge(
379
+ "REQUEST_METHOD" => "POST",
380
+ "rack.input" => StringIO.new(URI.encode_www_form(parameters))
381
+ )
382
+
383
+ assert_equal expected_form_hash, @client.send(:request_information, post_body_env_hash)[:form]
384
+ ensure
385
+ Raygun.configuration.filter_parameters = nil
386
+ end
387
+
388
+ def test_ip_address_from_action_dispatch
389
+ env_hash = sample_env_hash.merge({
390
+ "action_dispatch.remote_ip"=> "123.456.789.012"
391
+ })
392
+
393
+ assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
394
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
395
+ end
396
+
397
+ def test_ip_address_from_old_action_dispatch
398
+ old_action_dispatch_ip = FakeActionDispatcherIp.new("123.456.789.012")
399
+ env_hash = sample_env_hash.merge({
400
+ "action_dispatch.remote_ip"=> old_action_dispatch_ip
401
+ })
402
+
403
+ assert_equal old_action_dispatch_ip, @client.send(:ip_address_from, env_hash)
404
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
405
+ end
406
+
407
+ def test_ip_address_from_raygun_specific_key
408
+ env_hash = sample_env_hash.merge({
409
+ "raygun.remote_ip"=>"123.456.789.012"
410
+ })
411
+
412
+ assert_equal "123.456.789.012", @client.send(:ip_address_from, env_hash)
413
+ assert_equal "123.456.789.012", @client.send(:request_information, env_hash)[:iPAddress]
414
+ end
415
+
416
+ def test_ip_address_returns_not_available_if_not_set
417
+ env_hash = sample_env_hash.dup
418
+ env_hash.delete("REMOTE_ADDR")
419
+
420
+ assert_equal "(Not Available)", @client.send(:ip_address_from, env_hash)
421
+ end
422
+
423
+ def test_setting_up_http_proxy
424
+ begin
425
+ Raygun.configuration.proxy_settings[:address] = "http://proxy.com"
426
+ Raygun::Client.expects(:http_proxy).with("http://proxy.com", "80", nil, nil)
427
+
428
+ Raygun.track_exceptions do
429
+ raise TestException.new
430
+ end
431
+ ensure
432
+ Raygun.configuration.proxy_settings = {}
433
+ end
434
+ end
435
+
436
+ def test_filter_payload_with_whitelist_never_filters_toplevel
437
+ Timecop.freeze do
438
+ Raygun.configuration.filter_payload_with_whitelist = true
439
+ Raygun.configuration.whitelist_payload_shape = {}
440
+
441
+ e = test_exception
442
+
443
+ assert_equal Time.now.utc.iso8601, @client.send(:build_payload_hash, e)[:occurredOn]
444
+ assert_equal Hash, @client.send(:build_payload_hash, e)[:details].class
445
+ end
446
+ end
447
+
448
+ def test_filter_payload_with_whitelist_never_filters_client
449
+ Raygun.configuration.filter_payload_with_whitelist = true
450
+ Raygun.configuration.whitelist_payload_shape = {}
451
+
452
+ client_details = @client.send(:client_details)
453
+
454
+ assert_equal client_details, @client.send(:build_payload_hash, test_exception)[:details][:client]
455
+ end
456
+
457
+ def test_filter_payload_with_whitelist_default_error
458
+ Raygun.configuration.filter_payload_with_whitelist = true
459
+
460
+ details = @client.send(:build_payload_hash, test_exception)[:details]
461
+
462
+ assert_equal exception_hash, details[:error]
463
+ end
464
+
465
+ def test_filter_payload_with_whitelist_exclude_error_keys
466
+ Raygun.configuration.filter_payload_with_whitelist = true
467
+ Raygun.configuration.whitelist_payload_shape = {
468
+ error: {
469
+ className: true,
470
+ message: true,
471
+ stackTrace: true
472
+ }
473
+ }
474
+
475
+ details = @client.send(:build_payload_hash, test_exception)[:details]
476
+
477
+ assert_equal exception_hash, details[:error]
478
+ end
479
+
480
+ def test_filter_payload_with_whitelist_exclude_error_except_stacktrace
481
+ Raygun.configuration.filter_payload_with_whitelist = true
482
+ Raygun.configuration.whitelist_payload_shape = {
483
+ error: {
484
+ className: true,
485
+ message: true,
486
+ }
487
+ }
488
+
489
+ details = @client.send(:build_payload_hash, test_exception)[:details]
490
+
491
+ expected_hash = exception_hash.merge({
492
+ stackTrace: "[FILTERED]"
493
+ })
494
+
495
+ assert_equal expected_hash, details[:error]
496
+ end
497
+
498
+ def test_filter_payload_with_whitelist_proc
499
+ Raygun.configuration.filter_payload_with_whitelist = true
500
+ Raygun.configuration.whitelist_payload_shape do |payload|
501
+ payload
502
+ end
503
+
504
+ details = @client.send(:build_payload_hash, test_exception)[:details]
505
+
506
+ assert_equal exception_hash, details[:error]
507
+ end
508
+
509
+ def test_filter_payload_with_whitelist_default_request_post
510
+ Raygun.configuration.filter_payload_with_whitelist = true
511
+
512
+ post_body_env_hash = sample_env_hash.merge(
513
+ "CONTENT_TYPE" => 'application/x-www-form-urlencoded',
514
+ "REQUEST_METHOD" => "POST",
515
+ "rack.input"=>StringIO.new("a=b&c=4945438&password=swordfish")
516
+ )
517
+
518
+ details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
519
+
520
+ expected_hash = {
521
+ hostName: "localhost",
522
+ url: "/",
523
+ httpMethod: "POST",
524
+ iPAddress: "127.0.0.1",
525
+ queryString: { },
526
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
527
+ form: { "a" => "[FILTERED]", "c" => "[FILTERED]", "password" => "[FILTERED]" },
528
+ rawData: {}
529
+ }
530
+
531
+ assert_equal expected_hash, details[:request]
532
+ end
533
+
534
+ def test_filter_payload_with_whitelist_request_post_except_formkey
535
+ Raygun.configuration.filter_payload_with_whitelist = true
536
+ shape = Raygun.configuration.whitelist_payload_shape.dup
537
+ shape[:request] = Raygun.configuration.whitelist_payload_shape[:request].merge(
538
+ form: {
539
+ username: true
540
+ }
541
+ )
542
+ Raygun.configuration.whitelist_payload_shape = shape
543
+
544
+ post_body_env_hash = sample_env_hash.merge(
545
+ "REQUEST_METHOD" => "POST",
546
+ "rack.input"=>StringIO.new("username=foo&password=swordfish")
547
+ )
548
+
549
+ details = @client.send(:build_payload_hash, test_exception, post_body_env_hash)[:details]
550
+
551
+ expected_hash = {
552
+ hostName: "localhost",
553
+ url: "/",
554
+ httpMethod: "POST",
555
+ iPAddress: "127.0.0.1",
556
+ queryString: { },
557
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
558
+ form: { "username" => "foo", "password" => "[FILTERED]" },
559
+ rawData: {}
560
+ }
561
+
562
+ assert_equal expected_hash, details[:request]
563
+ end
564
+
565
+ def test_filter_payload_with_whitelist_default_request_get
566
+ Raygun.configuration.filter_payload_with_whitelist = true
567
+
568
+ env_hash = sample_env_hash.merge({
569
+ "QUERY_STRING"=>"a=b&c=4945438",
570
+ "REQUEST_URI"=>"/?a=b&c=4945438",
571
+ })
572
+ expected_hash = {
573
+ hostName: "localhost",
574
+ url: "/",
575
+ httpMethod: "GET",
576
+ iPAddress: "127.0.0.1",
577
+ queryString: { "a" => "b", "c" => "4945438" },
578
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
579
+ form: {},
580
+ rawData: nil
581
+ }
582
+
583
+ details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
584
+
585
+ assert_equal expected_hash, details[:request]
586
+ end
587
+
588
+ def test_filter_payload_with_whitelist_default_request_get_except_querystring
589
+ Raygun.configuration.filter_payload_with_whitelist = true
590
+ shape = Raygun.configuration.whitelist_payload_shape.dup
591
+ shape[:request] = Raygun::Configuration::DEFAULT_WHITELIST_PAYLOAD_SHAPE_REQUEST.dup.tap do |h|
592
+ h.delete(:queryString)
593
+ end
594
+ Raygun.configuration.whitelist_payload_shape = shape
595
+
596
+ expected_hash = {
597
+ hostName: "localhost",
598
+ url: "/",
599
+ httpMethod: "GET",
600
+ iPAddress: "127.0.0.1",
601
+ queryString: "[FILTERED]",
602
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
603
+ form: {},
604
+ rawData: nil
605
+ }
606
+
607
+ details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
608
+
609
+ assert_equal expected_hash, details[:request]
610
+ end
611
+
612
+ def test_filter_payload_with_whitelist_being_false_does_not_filter_query_string
613
+ Raygun.configuration.filter_payload_with_whitelist = false
614
+
615
+ env_hash = sample_env_hash.merge({
616
+ "QUERY_STRING"=>"a=b&c=4945438",
617
+ "REQUEST_URI"=>"/?a=b&c=4945438",
618
+ })
619
+ expected_hash = {
620
+ hostName: "localhost",
621
+ url: "/",
622
+ httpMethod: "GET",
623
+ iPAddress: "127.0.0.1",
624
+ queryString: { "a" => "b", "c" => "4945438" },
625
+ headers: { "Version"=>"HTTP/1.1", "Host"=>"localhost:3000", "Cookie"=>"cookieval" },
626
+ form: {},
627
+ rawData: nil
628
+ }
629
+
630
+ details = @client.send(:build_payload_hash, test_exception, env_hash)[:details]
631
+
632
+ assert_equal expected_hash, details[:request]
633
+ end
634
+
635
+ def test_filter_payload_with_whitelist_request_specific_keys
636
+ Raygun.configuration.filter_payload_with_whitelist = true
637
+ Raygun.configuration.whitelist_payload_shape = {
638
+ request: {
639
+ url: true,
640
+ httpMethod: true,
641
+ hostName: true
642
+ }
643
+ }
644
+
645
+ details = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details]
646
+
647
+ expected_hash = {
648
+ hostName: "localhost",
649
+ url: "/",
650
+ httpMethod: "GET",
651
+ iPAddress: "[FILTERED]",
652
+ queryString: "[FILTERED]",
653
+ headers: "[FILTERED]",
654
+ form: "[FILTERED]",
655
+ rawData: "[FILTERED]"
656
+ }
657
+
658
+ assert_equal expected_hash, details[:request]
659
+ end
660
+
661
+
662
+ def test_filter_payload_with_whitelist_and_filter_parameters_applies_both
663
+ Raygun.configuration.filter_parameters = [:password]
664
+ Raygun.configuration.filter_payload_with_whitelist = true
665
+ Raygun.configuration.whitelist_payload_shape = proc do |payload|
666
+ payload[:request][:headers]["Cookie"] = "[FILTERED]"
667
+ payload
668
+ end
669
+
670
+ parameters = {
671
+ "something_normal" => "hello",
672
+ "password" => "wouldntyouliketoknow"
673
+ }
674
+
675
+ post_body_env_hash = sample_env_hash.merge(
676
+ "REQUEST_METHOD" => "POST",
677
+ "rack.input" => StringIO.new(URI.encode_www_form(parameters))
678
+ )
679
+
680
+ payload = @client.send(:build_payload_hash, test_exception, post_body_env_hash)
681
+ request_payload = payload[:details][:request]
682
+
683
+ expected_form = {
684
+ "something_normal" => "hello",
685
+ "password" => "[FILTERED]"
686
+ }
687
+
688
+ assert_equal expected_form, request_payload[:form]
689
+
690
+ expected_headers = {
691
+ "Version" => "HTTP/1.1",
692
+ "Host" => "localhost:3000",
693
+ "Cookie" => "[FILTERED]"
694
+ }
695
+
696
+ assert_equal expected_headers, request_payload[:headers]
697
+ end
698
+
699
+ def test_build_payload_hash_adds_affected_user_details_when_supplied_with_user
700
+ user = OpenStruct.new(id: '123', email: 'test@email.com', first_name: 'Taylor')
701
+ expected_details = {
702
+ :isAnonymous => false,
703
+ :identifier => '123',
704
+ :email => 'test@email.com',
705
+ :firstName => 'Taylor',
706
+ }
707
+
708
+ user_details = @client.send(:build_payload_hash, test_exception, sample_env_hash, user)[:details][:user]
709
+
710
+ assert_equal expected_details, user_details
711
+ end
712
+
713
+ def test_build_payload_includes_breadcrumbs
714
+ ::Raygun::Breadcrumbs::Store.initialize
715
+ ::Raygun::Breadcrumbs::Store.record(message: "foo")
716
+
717
+ breadcrumbs = @client.send(:build_payload_hash, test_exception, sample_env_hash)[:details][:breadcrumbs]
718
+ ::Raygun::Breadcrumbs::Store.clear
719
+
720
+ assert_equal breadcrumbs.length, 1
721
+ assert breadcrumbs[0].is_a? Hash
722
+ end
723
+
724
+ def test_raw_data_does_not_crash_on_buffer_without_pos
725
+ buffer = StringIO.new('123456789')
726
+ rack_env = {
727
+ REQUEST_METHOD: 'POST',
728
+ 'rack.input' => buffer
729
+ }
730
+
731
+ buffer.instance_eval('undef :pos')
732
+
733
+ raw_data = @client.send(:raw_data, rack_env)
734
+
735
+ assert_equal('123456789', raw_data)
736
+ end
737
+
738
+ private
739
+
740
+ def test_exception
741
+ e = TestException.new
742
+ e.set_backtrace(["/some/folder/some_file.rb:123:in `some_method_name'",
743
+ "/another/path/foo.rb:1234:in `block (3 levels) run'"])
744
+
745
+ e
746
+ end
747
+
748
+ def nest_exceptions(outer_exception, inner_exception)
749
+ begin
750
+ begin
751
+ raise inner_exception.class, inner_exception.message
752
+ rescue => e
753
+ e.set_backtrace inner_exception.backtrace
754
+ raise outer_exception.class, outer_exception.message
755
+ end
756
+ rescue => nested_exception
757
+ nested_exception.set_backtrace outer_exception.backtrace
758
+ end
759
+
760
+ nested_exception
761
+ end
762
+
763
+ def exception_hash
764
+ {
765
+ className: "ClientTest::TestException",
766
+ message: "A test message",
767
+ stackTrace: [
768
+ { lineNumber: "123", fileName: "/some/folder/some_file.rb", methodName: "some_method_name" },
769
+ { lineNumber: "1234", fileName: "/another/path/foo.rb", methodName: "block (3 levels) run"}
770
+ ]
771
+ }
772
+ end
773
+
774
+ def sample_env_hash
775
+ {
776
+ "SERVER_NAME"=>"localhost",
777
+ "REQUEST_METHOD"=>"GET",
778
+ "REQUEST_PATH"=>"/",
779
+ "PATH_INFO"=>"/",
780
+ "QUERY_STRING"=>"",
781
+ "REQUEST_URI"=>"/",
782
+ "HTTP_VERSION"=>"HTTP/1.1",
783
+ "HTTP_HOST"=>"localhost:3000",
784
+ "HTTP_COOKIE"=>"cookieval",
785
+ "GATEWAY_INTERFACE"=>"CGI/1.2",
786
+ "SERVER_PORT"=>"3000",
787
+ "SERVER_PROTOCOL"=>"HTTP/1.1",
788
+ "SCRIPT_NAME"=>"",
789
+ "REMOTE_ADDR"=>"127.0.0.1"
790
+ }
791
+ end
792
+ end