airbrake-ruby 4.15.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/async_sender.rb +4 -2
  3. data/lib/airbrake-ruby/backtrace.rb +6 -5
  4. data/lib/airbrake-ruby/config/processor.rb +77 -0
  5. data/lib/airbrake-ruby/config/validator.rb +6 -0
  6. data/lib/airbrake-ruby/config.rb +44 -35
  7. data/lib/airbrake-ruby/context.rb +51 -0
  8. data/lib/airbrake-ruby/file_cache.rb +1 -1
  9. data/lib/airbrake-ruby/filter_chain.rb +3 -0
  10. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  11. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  12. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  14. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +3 -4
  15. data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
  16. data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
  17. data/lib/airbrake-ruby/filters/keys_filter.rb +23 -15
  18. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  19. data/lib/airbrake-ruby/filters/sql_filter.rb +11 -11
  20. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  21. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -3
  22. data/lib/airbrake-ruby/grouppable.rb +1 -1
  23. data/lib/airbrake-ruby/ignorable.rb +1 -2
  24. data/lib/airbrake-ruby/mergeable.rb +1 -1
  25. data/lib/airbrake-ruby/monotonic_time.rb +1 -1
  26. data/lib/airbrake-ruby/notice.rb +1 -8
  27. data/lib/airbrake-ruby/notice_notifier.rb +4 -4
  28. data/lib/airbrake-ruby/performance_breakdown.rb +1 -6
  29. data/lib/airbrake-ruby/performance_notifier.rb +40 -54
  30. data/lib/airbrake-ruby/promise.rb +1 -0
  31. data/lib/airbrake-ruby/query.rb +1 -6
  32. data/lib/airbrake-ruby/queue.rb +1 -8
  33. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  34. data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
  35. data/lib/airbrake-ruby/remote_settings.rb +128 -0
  36. data/lib/airbrake-ruby/request.rb +1 -8
  37. data/lib/airbrake-ruby/stat.rb +2 -13
  38. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  39. data/lib/airbrake-ruby/tdigest.rb +12 -9
  40. data/lib/airbrake-ruby/thread_pool.rb +9 -6
  41. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  42. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  43. data/lib/airbrake-ruby/truncator.rb +8 -2
  44. data/lib/airbrake-ruby/version.rb +11 -1
  45. data/lib/airbrake-ruby.rb +44 -54
  46. data/spec/airbrake_spec.rb +178 -92
  47. data/spec/async_sender_spec.rb +10 -8
  48. data/spec/backtrace_spec.rb +39 -36
  49. data/spec/benchmark_spec.rb +7 -5
  50. data/spec/code_hunk_spec.rb +26 -17
  51. data/spec/config/processor_spec.rb +167 -0
  52. data/spec/config/validator_spec.rb +23 -3
  53. data/spec/config_spec.rb +43 -55
  54. data/spec/context_spec.rb +54 -0
  55. data/spec/deploy_notifier_spec.rb +6 -4
  56. data/spec/file_cache_spec.rb +1 -0
  57. data/spec/filter_chain_spec.rb +29 -24
  58. data/spec/filters/context_filter_spec.rb +14 -5
  59. data/spec/filters/dependency_filter_spec.rb +3 -1
  60. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  61. data/spec/filters/gem_root_filter_spec.rb +9 -6
  62. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  63. data/spec/filters/{git_repository_filter.rb → git_repository_filter_spec.rb} +26 -15
  64. data/spec/filters/git_revision_filter_spec.rb +20 -20
  65. data/spec/filters/keys_allowlist_spec.rb +26 -16
  66. data/spec/filters/keys_blocklist_spec.rb +35 -18
  67. data/spec/filters/root_directory_filter_spec.rb +7 -7
  68. data/spec/filters/sql_filter_spec.rb +28 -28
  69. data/spec/filters/system_exit_filter_spec.rb +4 -2
  70. data/spec/filters/thread_filter_spec.rb +16 -14
  71. data/spec/loggable_spec.rb +2 -2
  72. data/spec/monotonic_time_spec.rb +8 -6
  73. data/spec/nested_exception_spec.rb +46 -46
  74. data/spec/notice_notifier/options_spec.rb +25 -15
  75. data/spec/notice_notifier_spec.rb +54 -49
  76. data/spec/notice_spec.rb +7 -3
  77. data/spec/performance_breakdown_spec.rb +0 -12
  78. data/spec/performance_notifier_spec.rb +69 -87
  79. data/spec/promise_spec.rb +38 -32
  80. data/spec/query_spec.rb +1 -11
  81. data/spec/queue_spec.rb +1 -13
  82. data/spec/remote_settings/callback_spec.rb +162 -0
  83. data/spec/remote_settings/settings_data_spec.rb +348 -0
  84. data/spec/remote_settings_spec.rb +201 -0
  85. data/spec/request_spec.rb +1 -13
  86. data/spec/response_spec.rb +34 -12
  87. data/spec/spec_helper.rb +4 -4
  88. data/spec/stashable_spec.rb +5 -5
  89. data/spec/stat_spec.rb +7 -14
  90. data/spec/sync_sender_spec.rb +52 -17
  91. data/spec/tdigest_spec.rb +61 -56
  92. data/spec/thread_pool_spec.rb +67 -58
  93. data/spec/time_truncate_spec.rb +23 -6
  94. data/spec/timed_trace_spec.rb +32 -30
  95. data/spec/truncator_spec.rb +72 -43
  96. metadata +67 -51
@@ -2,7 +2,7 @@ RSpec.describe Airbrake::Backtrace do
2
2
  describe ".parse" do
3
3
  context "UNIX backtrace" do
4
4
  let(:parsed_backtrace) do
5
- # rubocop:disable Metrics/LineLength, Style/HashSyntax, Layout/SpaceAroundOperators, Layout/SpaceInsideHashLiteralBraces
5
+ # rubocop:disable Layout/LineLength, Style/HashSyntax, Layout/SpaceAroundOperators, Layout/SpaceInsideHashLiteralBraces
6
6
  [{:file=>"/home/kyrylo/code/airbrake/ruby/spec/spec_helper.rb", :line=>23, :function=>"<top (required)>"},
7
7
  {:file=>"/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb", :line=>54, :function=>"require"},
8
8
  {:file=>"/opt/rubies/ruby-2.2.2/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb", :line=>54, :function=>"require"},
@@ -16,7 +16,7 @@ RSpec.describe Airbrake::Backtrace do
16
16
  {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>73, :function=>"run"},
17
17
  {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/lib/rspec/core/runner.rb", :line=>41, :function=>"invoke"},
18
18
  {:file=>"/home/kyrylo/.gem/ruby/2.2.2/gems/rspec-core-3.3.2/exe/rspec", :line=>4, :function=>"<main>"}]
19
- # rubocop:enable Metrics/LineLength, Style/HashSyntax, Layout/SpaceAroundOperators, Layout/SpaceInsideHashLiteralBraces
19
+ # rubocop:enable Layout/LineLength, Style/HashSyntax, Layout/SpaceAroundOperators, Layout/SpaceInsideHashLiteralBraces
20
20
  end
21
21
 
22
22
  it "returns a properly formatted array of hashes" do
@@ -34,10 +34,10 @@ RSpec.describe Airbrake::Backtrace do
34
34
  let(:ex) { AirbrakeTestError.new.tap { |e| e.set_backtrace(windows_bt) } }
35
35
 
36
36
  let(:parsed_backtrace) do
37
- # rubocop:disable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
37
+ # rubocop:disable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
38
38
  [{:file=>"C:/Program Files/Server/app/models/user.rb", :line=>13, :function=>"magic"},
39
39
  {:file=>"C:/Program Files/Server/app/controllers/users_controller.rb", :line=>8, :function=>"index"}]
40
- # rubocop:enable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
40
+ # rubocop:enable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
41
41
  end
42
42
 
43
43
  it "returns a properly formatted array of hashes" do
@@ -47,7 +47,7 @@ RSpec.describe Airbrake::Backtrace do
47
47
 
48
48
  context "JRuby Java exceptions" do
49
49
  let(:backtrace_array) do
50
- # rubocop:disable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
50
+ # rubocop:disable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
51
51
  [{:file=>"InstanceMethodInvoker.java", :line=>26, :function=>"org.jruby.java.invokers.InstanceMethodInvoker.call"},
52
52
  {:file=>"Interpreter.java", :line=>126, :function=>"org.jruby.ir.interpreter.Interpreter.INTERPRET_EVAL"},
53
53
  {:file=>"RubyKernel$INVOKER$s$0$3$eval19.gen", :line=>nil, :function=>"org.jruby.RubyKernel$INVOKER$s$0$3$eval19.call"},
@@ -59,7 +59,7 @@ RSpec.describe Airbrake::Backtrace do
59
59
  {:file=>"Compiler.java", :line=>111, :function=>"org.jruby.ir.Compiler$1.load"},
60
60
  {:file=>"Main.java", :line=>225, :function=>"org.jruby.Main.run"},
61
61
  {:file=>"Main.java", :line=>197, :function=>"org.jruby.Main.main"}]
62
- # rubocop:enable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
62
+ # rubocop:enable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
63
63
  end
64
64
 
65
65
  it "returns a properly formatted array of hashes" do
@@ -72,21 +72,21 @@ RSpec.describe Airbrake::Backtrace do
72
72
 
73
73
  context "JRuby classloader exceptions" do
74
74
  let(:backtrace) do
75
- # rubocop:disable Metrics/LineLength
75
+ # rubocop:disable Layout/LineLength
76
76
  ['uri_3a_classloader_3a_.META_minus_INF.jruby_dot_home.lib.ruby.stdlib.net.protocol.rbuf_fill(uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/net/protocol.rb:158)',
77
77
  'bin.processors.image_uploader.block in make_streams(bin/processors/image_uploader.rb:21)',
78
78
  'uri_3a_classloader_3a_.gems.faye_minus_websocket_minus_0_dot_10_dot_5.lib.faye.websocket.api.invokeOther13:dispatch_event(uri_3a_classloader_3a_/gems/faye_minus_websocket_minus_0_dot_10_dot_5/lib/faye/websocket/uri:classloader:/gems/faye-websocket-0.10.5/lib/faye/websocket/api.rb:109)',
79
79
  'tmp.jruby9022301782566983632extract.$dot.META_minus_INF.rails.file(/tmp/jruby9022301782566983632extract/./META-INF/rails.rb:13)']
80
- # rubocop:enable Metrics/LineLength
80
+ # rubocop:enable Layout/LineLength
81
81
  end
82
82
 
83
83
  let(:parsed_backtrace) do
84
- # rubocop:disable Metrics/LineLength
84
+ # rubocop:disable Layout/LineLength
85
85
  [{ file: 'uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/net/protocol.rb', line: 158, function: 'uri_3a_classloader_3a_.META_minus_INF.jruby_dot_home.lib.ruby.stdlib.net.protocol.rbuf_fill' },
86
86
  { file: 'bin/processors/image_uploader.rb', line: 21, function: 'bin.processors.image_uploader.block in make_streams' },
87
87
  { file: 'uri_3a_classloader_3a_/gems/faye_minus_websocket_minus_0_dot_10_dot_5/lib/faye/websocket/uri:classloader:/gems/faye-websocket-0.10.5/lib/faye/websocket/api.rb', line: 109, function: 'uri_3a_classloader_3a_.gems.faye_minus_websocket_minus_0_dot_10_dot_5.lib.faye.websocket.api.invokeOther13:dispatch_event' },
88
88
  { file: '/tmp/jruby9022301782566983632extract/./META-INF/rails.rb', line: 13, function: 'tmp.jruby9022301782566983632extract.$dot.META_minus_INF.rails.file' }]
89
- # rubocop:enable Metrics/LineLength
89
+ # rubocop:enable Layout/LineLength
90
90
  end
91
91
 
92
92
  let(:ex) { JavaAirbrakeTestError.new.tap { |e| e.set_backtrace(backtrace) } }
@@ -99,19 +99,19 @@ RSpec.describe Airbrake::Backtrace do
99
99
 
100
100
  context "JRuby non-throwable exceptions" do
101
101
  let(:backtrace) do
102
- # rubocop:disable Metrics/LineLength
102
+ # rubocop:disable Layout/LineLength
103
103
  ['org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(org/postgresql/core/v3/ConnectionFactoryImpl.java:257)',
104
104
  'org.postgresql.core.ConnectionFactory.openConnection(org/postgresql/core/ConnectionFactory.java:65)',
105
105
  'org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(org/postgresql/jdbc2/AbstractJdbc2Connection.java:149)']
106
- # rubocop:enable Metrics/LineLength
106
+ # rubocop:enable Layout/LineLength
107
107
  end
108
108
 
109
109
  let(:parsed_backtrace) do
110
- # rubocop:disable Metrics/LineLength
110
+ # rubocop:disable Layout/LineLength
111
111
  [{ file: 'org/postgresql/core/v3/ConnectionFactoryImpl.java', line: 257, function: 'org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl' },
112
112
  { file: 'org/postgresql/core/ConnectionFactory.java', line: 65, function: 'org.postgresql.core.ConnectionFactory.openConnection' },
113
113
  { file: 'org/postgresql/jdbc2/AbstractJdbc2Connection.java', line: 149, function: 'org.postgresql.jdbc2.AbstractJdbc2Connection.<init>' }]
114
- # rubocop:enable Metrics/LineLength
114
+ # rubocop:enable Layout/LineLength
115
115
  end
116
116
 
117
117
  let(:ex) { AirbrakeTestError.new.tap { |e| e.set_backtrace(backtrace) } }
@@ -123,22 +123,22 @@ RSpec.describe Airbrake::Backtrace do
123
123
 
124
124
  context "generic backtrace" do
125
125
  context "when function is absent" do
126
- # rubocop:disable Metrics/LineLength
126
+ # rubocop:disable Layout/LineLength
127
127
  let(:generic_bt) do
128
128
  ["/home/bingo/bango/assets/stylesheets/error_pages.scss:139:in `animation'",
129
129
  "/home/bingo/bango/assets/stylesheets/error_pages.scss:139",
130
130
  "/home/bingo/.gem/ruby/2.2.2/gems/sass-3.4.20/lib/sass/tree/visitors/perform.rb:349:in `block in visit_mixin'"]
131
131
  end
132
- # rubocop:enable Metrics/LineLength
132
+ # rubocop:enable Layout/LineLength
133
133
 
134
134
  let(:ex) { AirbrakeTestError.new.tap { |e| e.set_backtrace(generic_bt) } }
135
135
 
136
136
  let(:parsed_backtrace) do
137
- # rubocop:disable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
137
+ # rubocop:disable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
138
138
  [{:file=>"/home/bingo/bango/assets/stylesheets/error_pages.scss", :line=>139, :function=>"animation"},
139
139
  {:file=>"/home/bingo/bango/assets/stylesheets/error_pages.scss", :line=>139, :function=>nil},
140
140
  {:file=>"/home/bingo/.gem/ruby/2.2.2/gems/sass-3.4.20/lib/sass/tree/visitors/perform.rb", :line=>349, :function=>"block in visit_mixin"}]
141
- # rubocop:enable Metrics/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
141
+ # rubocop:enable Layout/LineLength, Style/HashSyntax, Layout/SpaceInsideHashLiteralBraces, Layout/SpaceAroundOperators
142
142
  end
143
143
 
144
144
  it "returns a properly formatted array of hashes" do
@@ -177,10 +177,13 @@ RSpec.describe Airbrake::Backtrace do
177
177
  end
178
178
 
179
179
  it "logs frames that cannot be parsed" do
180
- expect(Airbrake::Loggable.instance).to receive(:error).with(
180
+ allow(Airbrake::Loggable.instance).to receive(:error)
181
+
182
+ described_class.parse(ex)
183
+
184
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
181
185
  /can't parse 'a b c 1 23 321 .rb'/,
182
186
  )
183
- described_class.parse(ex)
184
187
  end
185
188
  end
186
189
 
@@ -277,9 +280,9 @@ RSpec.describe Airbrake::Backtrace do
277
280
  93 => ' begin',
278
281
  94 => ' json = @payload.to_json',
279
282
  95 => ' rescue *JSON_EXCEPTIONS => ex',
280
- # rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
283
+ # rubocop:disable Layout/LineLength,Lint/InterpolationCheck
281
284
  96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
282
- # rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
285
+ # rubocop:enable Layout/LineLength,Lint/InterpolationCheck
283
286
  },
284
287
  },
285
288
  {
@@ -298,9 +301,9 @@ RSpec.describe Airbrake::Backtrace do
298
301
  it "attaches code to those frames files of which match root_directory" do
299
302
  ex = RuntimeError.new
300
303
  backtrace = [
301
- project_root_path('code.rb') + ":94:in `to_json'",
302
- fixture_path('notroot.txt' + ":3:in `pineapple'"),
303
- project_root_path('vendor/bundle/ignored_file.rb') + ":2:in `ignore_me'",
304
+ "#{project_root_path('code.rb')}:94:in `to_json'",
305
+ fixture_path("notroot.txt:3:in `pineapple'"),
306
+ "#{project_root_path('vendor/bundle/ignored_file.rb')}:2:in `ignore_me'",
304
307
  ]
305
308
  ex.set_backtrace(backtrace)
306
309
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
@@ -325,9 +328,9 @@ RSpec.describe Airbrake::Backtrace do
325
328
  93 => ' begin',
326
329
  94 => ' json = @payload.to_json',
327
330
  95 => ' rescue *JSON_EXCEPTIONS => ex',
328
- # rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
331
+ # rubocop:disable Layout/LineLength,Lint/InterpolationCheck
329
332
  96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
330
- # rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
333
+ # rubocop:enable Layout/LineLength,Lint/InterpolationCheck
331
334
  },
332
335
  },
333
336
  ]
@@ -335,7 +338,7 @@ RSpec.describe Airbrake::Backtrace do
335
338
 
336
339
  it "attaches code to those frames files of which match root_directory" do
337
340
  ex = RuntimeError.new
338
- ex.set_backtrace([project_root_path('code.rb') + ":94:in `to_json'"])
341
+ ex.set_backtrace(["#{project_root_path('code.rb')}:94:in `to_json'"])
339
342
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
340
343
  end
341
344
  end
@@ -357,9 +360,9 @@ RSpec.describe Airbrake::Backtrace do
357
360
  93 => ' begin',
358
361
  94 => ' json = @payload.to_json',
359
362
  95 => ' rescue *JSON_EXCEPTIONS => ex',
360
- # rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
363
+ # rubocop:disable Layout/LineLength,Lint/InterpolationCheck
361
364
  96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
362
- # rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
365
+ # rubocop:enable Layout/LineLength,Lint/InterpolationCheck
363
366
  },
364
367
  },
365
368
  {
@@ -370,9 +373,9 @@ RSpec.describe Airbrake::Backtrace do
370
373
  93 => ' begin',
371
374
  94 => ' json = @payload.to_json',
372
375
  95 => ' rescue *JSON_EXCEPTIONS => ex',
373
- # rubocop:disable Metrics/LineLength,Lint/InterpolationCheck
376
+ # rubocop:disable Layout/LineLength,Lint/InterpolationCheck
374
377
  96 => ' @config.logger.debug("#{LOG_LABEL} `notice.to_json` failed: #{ex.class}: #{ex}")',
375
- # rubocop:enable Metrics/LineLength,Lint/InterpolationCheck
378
+ # rubocop:enable Layout/LineLength,Lint/InterpolationCheck
376
379
  97 => ' else',
377
380
  },
378
381
  },
@@ -387,9 +390,9 @@ RSpec.describe Airbrake::Backtrace do
387
390
  it "attaches code to first N frames" do
388
391
  ex = RuntimeError.new
389
392
  backtrace = [
390
- project_root_path('code.rb') + ":94:in `to_json'",
391
- project_root_path('code.rb') + ":95:in `to_json'",
392
- project_root_path('code.rb') + ":96:in `to_json'",
393
+ "#{project_root_path('code.rb')}:94:in `to_json'",
394
+ "#{project_root_path('code.rb')}:95:in `to_json'",
395
+ "#{project_root_path('code.rb')}:96:in `to_json'",
393
396
  ]
394
397
  ex.set_backtrace(backtrace)
395
398
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
@@ -417,7 +420,7 @@ RSpec.describe Airbrake::Backtrace do
417
420
 
418
421
  it "doesn't attach code to frames" do
419
422
  ex = RuntimeError.new
420
- backtrace = [project_root_path('code.rb') + ":94:in `to_json'"]
423
+ backtrace = ["#{project_root_path('code.rb')}:94:in `to_json'"]
421
424
  ex.set_backtrace(backtrace)
422
425
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
423
426
  end
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::Benchmark do
2
+ subject(:benchmark) { described_class.new }
3
+
2
4
  describe ".measure" do
3
5
  it "returns measured performance time" do
4
6
  expect(described_class.measure { '10' * 10 }).to be_kind_of(Numeric)
@@ -6,16 +8,16 @@ RSpec.describe Airbrake::Benchmark do
6
8
  end
7
9
 
8
10
  describe "#stop" do
9
- before { subject }
11
+ before { benchmark }
10
12
 
11
13
  context "when called one time" do
12
- its(:stop) { is_expected.to eq(true) }
14
+ its(:stop) { is_expected.to be(true) }
13
15
  end
14
16
 
15
17
  context "when called twice or more" do
16
- before { subject.stop }
18
+ before { benchmark.stop }
17
19
 
18
- its(:stop) { is_expected.to eq(false) }
20
+ its(:stop) { is_expected.to be(false) }
19
21
  end
20
22
  end
21
23
 
@@ -25,7 +27,7 @@ RSpec.describe Airbrake::Benchmark do
25
27
  end
26
28
 
27
29
  context "when #stop was called" do
28
- before { subject.stop }
30
+ before { benchmark.stop }
29
31
 
30
32
  its(:duration) { is_expected.to be > 0 }
31
33
  end
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::CodeHunk do
2
+ subject(:code_hunk) { described_class.new }
3
+
2
4
  after do
3
5
  %w[empty_file.rb code.rb banana.rb short_file.rb long_line.txt].each do |f|
4
6
  Airbrake::FileCache[project_root_path(f)] = nil
@@ -27,26 +29,30 @@ RSpec.describe Airbrake::CodeHunk do
27
29
  end
28
30
 
29
31
  context "when a file has less than NLINES lines before start line" do
30
- subject { described_class.new.get(project_root_path('code.rb'), 1) }
32
+ subject(:code_hunk) do
33
+ described_class.new.get(project_root_path('code.rb'), 1)
34
+ end
31
35
 
32
36
  it do
33
- is_expected.to(
37
+ expect(code_hunk).to(
34
38
  eq(
35
39
  1 => 'module Airbrake',
36
40
  2 => ' ##',
37
- # rubocop:disable Metrics/LineLength
41
+ # rubocop:disable Layout/LineLength
38
42
  3 => ' # Represents a chunk of information that is meant to be either sent to',
39
- # rubocop:enable Metrics/LineLength
43
+ # rubocop:enable Layout/LineLength
40
44
  ),
41
45
  )
42
46
  end
43
47
  end
44
48
 
45
49
  context "when a file has less than NLINES lines after end line" do
46
- subject { described_class.new.get(project_root_path('code.rb'), 222) }
50
+ subject(:code_hunk) do
51
+ described_class.new.get(project_root_path('code.rb'), 222)
52
+ end
47
53
 
48
54
  it do
49
- is_expected.to(
55
+ expect(code_hunk).to(
50
56
  eq(
51
57
  220 => ' end',
52
58
  221 => 'end',
@@ -56,12 +62,12 @@ RSpec.describe Airbrake::CodeHunk do
56
62
  end
57
63
 
58
64
  context "when a file has less than NLINES lines before and after" do
59
- subject do
65
+ subject(:code_hunk) do
60
66
  described_class.new.get(project_root_path('short_file.rb'), 2)
61
67
  end
62
68
 
63
69
  it do
64
- is_expected.to(
70
+ expect(code_hunk).to(
65
71
  eq(
66
72
  1 => 'module Banana',
67
73
  2 => ' attr_reader :bingo',
@@ -72,10 +78,12 @@ RSpec.describe Airbrake::CodeHunk do
72
78
  end
73
79
 
74
80
  context "when a file has enough lines before and after" do
75
- subject { described_class.new.get(project_root_path('code.rb'), 100) }
81
+ subject(:code_hunk) do
82
+ described_class.new.get(project_root_path('code.rb'), 100)
83
+ end
76
84
 
77
85
  it do
78
- is_expected.to(
86
+ expect(code_hunk).to(
79
87
  eq(
80
88
  98 => ' return json if json && json.bytesize <= MAX_NOTICE_SIZE',
81
89
  99 => ' end',
@@ -88,27 +96,28 @@ RSpec.describe Airbrake::CodeHunk do
88
96
  end
89
97
 
90
98
  context "when a line exceeds the length limit" do
91
- subject do
99
+ subject(:code_hunk) do
92
100
  described_class.new.get(project_root_path('long_line.txt'), 1)
93
101
  end
94
102
 
95
103
  it "strips the line" do
96
- expect(subject[1]).to eq('l' + 'o' * 196 + 'ng')
104
+ expect(code_hunk[1]).to eq("l#{'o' * 196}ng")
97
105
  end
98
106
  end
99
107
 
100
108
  context "when an error occurrs while fetching code" do
101
109
  before do
102
- expect(Airbrake::FileCache).to receive(:[]).and_raise(Errno::EACCES)
110
+ allow(Airbrake::Loggable.instance).to receive(:error)
111
+ allow(Airbrake::FileCache).to receive(:[]).and_raise(Errno::EACCES)
103
112
  end
104
113
 
105
114
  it "logs error and returns nil" do
106
- expect(Airbrake::Loggable.instance).to receive(:error).with(
107
- /can't read code hunk.+Permission denied/,
108
- )
109
- expect(subject.get(project_root_path('code.rb'), 1)).to(
115
+ expect(code_hunk.get(project_root_path('code.rb'), 1)).to(
110
116
  eq(1 => ''),
111
117
  )
118
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
119
+ /can't read code hunk.+Permission denied/,
120
+ )
112
121
  end
113
122
  end
114
123
  end
@@ -0,0 +1,167 @@
1
+ RSpec.describe Airbrake::Config::Processor do
2
+ let(:notifier) { Airbrake::NoticeNotifier.new }
3
+
4
+ describe "#process_blocklist" do
5
+ let(:config) { Airbrake::Config.new(blocklist_keys: %w[a b c]) }
6
+
7
+ context "when there ARE blocklist keys" do
8
+ it "adds the blocklist filter" do
9
+ described_class.new(config).process_blocklist(notifier)
10
+ expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist)).to be(true)
11
+ end
12
+ end
13
+
14
+ context "when there are NO blocklist keys" do
15
+ let(:config) { Airbrake::Config.new(blocklist_keys: %w[]) }
16
+
17
+ it "doesn't add the blocklist filter" do
18
+ described_class.new(config).process_blocklist(notifier)
19
+ expect(notifier.has_filter?(Airbrake::Filters::KeysBlocklist))
20
+ .to be(false)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe "#process_allowlist" do
26
+ let(:config) { Airbrake::Config.new(allowlist_keys: %w[a b c]) }
27
+
28
+ context "when there ARE allowlist keys" do
29
+ it "adds the allowlist filter" do
30
+ described_class.new(config).process_allowlist(notifier)
31
+ expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist)).to be(true)
32
+ end
33
+ end
34
+
35
+ context "when there are NO allowlist keys" do
36
+ let(:config) { Airbrake::Config.new(allowlist_keys: %w[]) }
37
+
38
+ it "doesn't add the allowlist filter" do
39
+ described_class.new(config).process_allowlist(notifier)
40
+ expect(notifier.has_filter?(Airbrake::Filters::KeysAllowlist))
41
+ .to be(false)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#process_remote_configuration" do
47
+ before do
48
+ allow(Airbrake::RemoteSettings).to receive(:poll)
49
+ end
50
+
51
+ context "when the config doesn't define a project_id" do
52
+ let(:config) { Airbrake::Config.new(project_id: nil) }
53
+
54
+ it "doesn't set remote settings" do
55
+ described_class.new(config).process_remote_configuration
56
+
57
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
58
+ end
59
+ end
60
+
61
+ context "when the config sets environment to 'test'" do
62
+ let(:config) { Airbrake::Config.new(project_id: 123, environment: 'test') }
63
+
64
+ it "doesn't set remote settings" do
65
+ described_class.new(config).process_remote_configuration
66
+
67
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
68
+ end
69
+ end
70
+
71
+ context "when the config sets :ignore_environments and :environment matches" do
72
+ let(:config) do
73
+ Airbrake::Config.new(
74
+ project_id: 123,
75
+ ignore_environments: %w[dev],
76
+ environment: 'dev',
77
+ )
78
+ end
79
+
80
+ it "doesn't set remote settings" do
81
+ described_class.new(config).process_remote_configuration
82
+
83
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
84
+ end
85
+ end
86
+
87
+ context "when the config defines a project_id" do
88
+ let(:config) do
89
+ Airbrake::Config.new(project_id: 123, environment: 'not-test')
90
+ end
91
+
92
+ it "sets remote settings" do
93
+ described_class.new(config).process_remote_configuration
94
+
95
+ expect(Airbrake::RemoteSettings).to have_received(:poll)
96
+ end
97
+ end
98
+
99
+ context "when the config disables the remote_config option" do
100
+ let(:config) { Airbrake::Config.new(project_id: 123, remote_config: false) }
101
+
102
+ it "doesn't set remote settings" do
103
+ described_class.new(config).process_remote_configuration
104
+
105
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#add_filters" do
111
+ context "when there's a root directory" do
112
+ let(:config) { Airbrake::Config.new(root_directory: '/abc') }
113
+
114
+ it "adds RootDirectoryFilter" do
115
+ described_class.new(config).add_filters(notifier)
116
+ expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
117
+ .to be(true)
118
+ end
119
+
120
+ it "adds GitRevisionFilter" do
121
+ described_class.new(config).add_filters(notifier)
122
+ expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
123
+ .to be(true)
124
+ end
125
+
126
+ it "adds GitRepositoryFilter" do
127
+ described_class.new(config).add_filters(notifier)
128
+ expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
129
+ .to be(true)
130
+ end
131
+
132
+ it "adds GitLastCheckoutFilter" do
133
+ described_class.new(config).add_filters(notifier)
134
+ expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
135
+ .to be(true)
136
+ end
137
+ end
138
+
139
+ context "when there's NO root directory" do
140
+ let(:config) { Airbrake::Config.new(root_directory: nil) }
141
+
142
+ it "doesn't add RootDirectoryFilter" do
143
+ described_class.new(config).add_filters(notifier)
144
+ expect(notifier.has_filter?(Airbrake::Filters::RootDirectoryFilter))
145
+ .to be(false)
146
+ end
147
+
148
+ it "doesn't add GitRevisionFilter" do
149
+ described_class.new(config).add_filters(notifier)
150
+ expect(notifier.has_filter?(Airbrake::Filters::GitRevisionFilter))
151
+ .to be(false)
152
+ end
153
+
154
+ it "doesn't add GitRepositoryFilter" do
155
+ described_class.new(config).add_filters(notifier)
156
+ expect(notifier.has_filter?(Airbrake::Filters::GitRepositoryFilter))
157
+ .to be(false)
158
+ end
159
+
160
+ it "doesn't add GitLastCheckoutFilter" do
161
+ described_class.new(config).add_filters(notifier)
162
+ expect(notifier.has_filter?(Airbrake::Filters::GitLastCheckoutFilter))
163
+ .to be(false)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -169,15 +169,35 @@ RSpec.describe Airbrake::Config::Validator do
169
169
  }
170
170
  end
171
171
 
172
- it "returns a rejected promise" do
172
+ it "returns a resolved promise" do
173
173
  promise = described_class.check_notify_ability(config)
174
174
  expect(promise).to be_resolved
175
175
  end
176
176
 
177
177
  it "warns about 'no effect'" do
178
- expect(config.logger).to receive(:warn)
179
- .with(/'ignore_environments' has no effect/)
178
+ allow(config.logger).to receive(:warn)
179
+
180
180
  described_class.check_notify_ability(config)
181
+
182
+ expect(config.logger).to have_received(:warn)
183
+ .with(/'ignore_environments' has no effect/)
184
+ end
185
+ end
186
+
187
+ context "when the error_notifications option is false" do
188
+ let(:config_params) do
189
+ {
190
+ project_id: valid_id,
191
+ project_key: valid_key,
192
+ error_notifications: false,
193
+ }
194
+ end
195
+
196
+ it "returns a rejected promise" do
197
+ promise = described_class.check_notify_ability(config)
198
+ expect(promise.value).to eq(
199
+ 'error' => "error notifications are disabled",
200
+ )
181
201
  end
182
202
  end
183
203
  end