raygun4ruby 3.2.3 → 3.2.4

Sign up to get free protection for your applications and to get access to all the features.
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