raygun4ruby 3.1.1 → 3.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +18 -18
  3. data/.rspec +1 -1
  4. data/.travis.yml +20 -12
  5. data/CHANGELOG.md +127 -109
  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 -182
  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 -30
  16. data/lib/raygun/breadcrumbs/store.rb +86 -76
  17. data/lib/raygun/client.rb +305 -302
  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/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 -0
  35. data/spec/dummy/Gemfile +47 -0
  36. data/spec/dummy/README.rdoc +28 -0
  37. data/spec/dummy/Rakefile +6 -6
  38. data/spec/dummy/app/assets/config/manifest.js +3 -3
  39. data/spec/dummy/app/assets/images/.keep +0 -0
  40. data/spec/dummy/app/assets/javascripts/application.js +13 -15
  41. data/spec/dummy/app/assets/stylesheets/application.css +15 -15
  42. data/spec/dummy/app/controllers/application_controller.rb +5 -2
  43. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  44. data/spec/dummy/app/controllers/home_controller.rb +4 -4
  45. data/spec/dummy/app/helpers/application_helper.rb +2 -2
  46. data/spec/dummy/app/{assets/javascripts/channels → mailers}/.keep +0 -0
  47. data/spec/dummy/{storage → app/models}/.keep +0 -0
  48. data/spec/dummy/app/models/concerns/.keep +0 -0
  49. data/spec/dummy/app/views/home/index.html.erb +3 -3
  50. data/spec/dummy/app/views/home/index.json.erb +1 -1
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -15
  52. data/spec/dummy/bin/bundle +3 -3
  53. data/spec/dummy/bin/rails +9 -4
  54. data/spec/dummy/bin/rake +9 -4
  55. data/spec/dummy/bin/setup +29 -36
  56. data/spec/dummy/bin/spring +17 -0
  57. data/spec/dummy/config.ru +4 -5
  58. data/spec/dummy/config/application.rb +26 -18
  59. data/spec/dummy/config/boot.rb +3 -5
  60. data/spec/dummy/config/database.yml +25 -25
  61. data/spec/dummy/config/environment.rb +5 -5
  62. data/spec/dummy/config/environments/development.rb +41 -61
  63. data/spec/dummy/config/environments/production.rb +79 -94
  64. data/spec/dummy/config/environments/test.rb +42 -46
  65. data/spec/dummy/config/initializers/assets.rb +11 -14
  66. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -7
  67. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -5
  68. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -4
  69. data/spec/dummy/config/initializers/inflections.rb +16 -16
  70. data/spec/dummy/config/initializers/mime_types.rb +4 -4
  71. data/spec/dummy/config/initializers/session_store.rb +3 -0
  72. data/spec/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  73. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -14
  74. data/spec/dummy/config/locales/en.yml +23 -33
  75. data/spec/dummy/config/routes.rb +58 -3
  76. data/spec/dummy/config/secrets.yml +22 -0
  77. data/spec/dummy/db/seeds.rb +7 -0
  78. data/spec/dummy/db/test.sqlite3 +0 -0
  79. data/spec/dummy/lib/assets/.keep +0 -0
  80. data/spec/dummy/{public/apple-touch-icon-precomposed.png → lib/tasks/.keep} +0 -0
  81. data/spec/dummy/public/404.html +67 -67
  82. data/spec/dummy/public/422.html +67 -67
  83. data/spec/dummy/public/500.html +66 -66
  84. data/spec/dummy/public/favicon.ico +0 -0
  85. data/spec/dummy/public/robots.txt +5 -0
  86. data/spec/dummy/{public/apple-touch-icon.png → test/controllers/.keep} +0 -0
  87. data/spec/dummy/test/fixtures/.keep +0 -0
  88. data/spec/dummy/test/helpers/.keep +0 -0
  89. data/spec/dummy/test/integration/.keep +0 -0
  90. data/spec/dummy/test/mailers/.keep +0 -0
  91. data/spec/dummy/test/models/.keep +0 -0
  92. data/spec/dummy/test/test_helper.rb +10 -0
  93. data/spec/dummy/vendor/assets/javascripts/.keep +0 -0
  94. data/spec/dummy/vendor/assets/stylesheets/.keep +0 -0
  95. data/spec/features/javascript_spec.rb +48 -48
  96. data/spec/rails_helper.rb +4 -4
  97. data/spec/raygun/breadcrumbs/breadcrumb_spec.rb +171 -134
  98. data/spec/raygun/breadcrumbs/store_spec.rb +170 -146
  99. data/spec/raygun/raygun_spec.rb +47 -47
  100. data/spec/services/apply_whitelist_filter_to_payload_spec.rb +251 -251
  101. data/spec/spec_helper.rb +24 -24
  102. data/spec/support/fake_logger.rb +17 -17
  103. data/test/integration/client_test.rb +19 -19
  104. data/test/test_helper.rb +72 -72
  105. data/test/unit/affected_user_test.rb +136 -136
  106. data/test/unit/client_test.rb +792 -790
  107. data/test/unit/configuration_test.rb +206 -206
  108. data/test/unit/raygun_test.rb +25 -25
  109. data/test/unit/resque_failure_test.rb +24 -24
  110. data/test/unit/sidekiq_failure_test.rb +32 -32
  111. metadata +42 -45
  112. data/spec/dummy/.ruby-version +0 -1
  113. data/spec/dummy/app/assets/javascripts/cable.js +0 -13
  114. data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
  115. data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
  116. data/spec/dummy/app/jobs/application_job.rb +0 -2
  117. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  118. data/spec/dummy/app/models/application_record.rb +0 -3
  119. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  120. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  121. data/spec/dummy/bin/update +0 -31
  122. data/spec/dummy/bin/yarn +0 -11
  123. data/spec/dummy/config/cable.yml +0 -10
  124. data/spec/dummy/config/initializers/application_controller_renderer.rb +0 -8
  125. data/spec/dummy/config/initializers/content_security_policy.rb +0 -25
  126. data/spec/dummy/config/puma.rb +0 -34
  127. data/spec/dummy/config/spring.rb +0 -6
  128. data/spec/dummy/config/storage.yml +0 -34
  129. data/spec/dummy/db/schema.rb +0 -15
  130. data/spec/dummy/package.json +0 -5
@@ -1,790 +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
-
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_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