raygun4ruby 3.2.0 → 3.2.5.pre

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