raygun4ruby 3.1.1 → 3.2.4

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