airbrake-ruby 4.1.0 → 5.0.0

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 (94) hide show
  1. checksums.yaml +5 -5
  2. data/lib/airbrake-ruby/async_sender.rb +22 -96
  3. data/lib/airbrake-ruby/backtrace.rb +8 -7
  4. data/lib/airbrake-ruby/benchmark.rb +39 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +1 -1
  6. data/lib/airbrake-ruby/config/processor.rb +84 -0
  7. data/lib/airbrake-ruby/config/validator.rb +9 -3
  8. data/lib/airbrake-ruby/config.rb +76 -20
  9. data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
  10. data/lib/airbrake-ruby/file_cache.rb +6 -0
  11. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +5 -5
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  18. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  19. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  20. data/lib/airbrake-ruby/filters/keys_filter.rb +39 -20
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +30 -6
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +4 -2
  25. data/lib/airbrake-ruby/grouppable.rb +12 -0
  26. data/lib/airbrake-ruby/ignorable.rb +1 -0
  27. data/lib/airbrake-ruby/inspectable.rb +2 -2
  28. data/lib/airbrake-ruby/loggable.rb +2 -2
  29. data/lib/airbrake-ruby/mergeable.rb +12 -0
  30. data/lib/airbrake-ruby/monotonic_time.rb +48 -0
  31. data/lib/airbrake-ruby/notice.rb +10 -20
  32. data/lib/airbrake-ruby/notice_notifier.rb +23 -42
  33. data/lib/airbrake-ruby/performance_breakdown.rb +52 -0
  34. data/lib/airbrake-ruby/performance_notifier.rb +126 -49
  35. data/lib/airbrake-ruby/promise.rb +1 -0
  36. data/lib/airbrake-ruby/query.rb +26 -11
  37. data/lib/airbrake-ruby/queue.rb +65 -0
  38. data/lib/airbrake-ruby/remote_settings/settings_data.rb +120 -0
  39. data/lib/airbrake-ruby/remote_settings.rb +145 -0
  40. data/lib/airbrake-ruby/request.rb +20 -6
  41. data/lib/airbrake-ruby/stashable.rb +15 -0
  42. data/lib/airbrake-ruby/stat.rb +34 -24
  43. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  44. data/lib/airbrake-ruby/tdigest.rb +43 -58
  45. data/lib/airbrake-ruby/thread_pool.rb +138 -0
  46. data/lib/airbrake-ruby/timed_trace.rb +58 -0
  47. data/lib/airbrake-ruby/truncator.rb +10 -4
  48. data/lib/airbrake-ruby/version.rb +11 -1
  49. data/lib/airbrake-ruby.rb +219 -53
  50. data/spec/airbrake_spec.rb +428 -9
  51. data/spec/async_sender_spec.rb +26 -110
  52. data/spec/backtrace_spec.rb +44 -44
  53. data/spec/benchmark_spec.rb +33 -0
  54. data/spec/code_hunk_spec.rb +11 -11
  55. data/spec/config/processor_spec.rb +209 -0
  56. data/spec/config/validator_spec.rb +23 -6
  57. data/spec/config_spec.rb +77 -7
  58. data/spec/deploy_notifier_spec.rb +2 -2
  59. data/spec/{file_cache.rb → file_cache_spec.rb} +2 -4
  60. data/spec/filter_chain_spec.rb +28 -1
  61. data/spec/filters/dependency_filter_spec.rb +1 -1
  62. data/spec/filters/gem_root_filter_spec.rb +9 -9
  63. data/spec/filters/git_last_checkout_filter_spec.rb +21 -4
  64. data/spec/filters/git_repository_filter.rb +1 -1
  65. data/spec/filters/git_revision_filter_spec.rb +13 -11
  66. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +29 -28
  67. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +39 -29
  68. data/spec/filters/root_directory_filter_spec.rb +9 -9
  69. data/spec/filters/sql_filter_spec.rb +110 -55
  70. data/spec/filters/system_exit_filter_spec.rb +1 -1
  71. data/spec/filters/thread_filter_spec.rb +33 -31
  72. data/spec/fixtures/project_root/code.rb +9 -9
  73. data/spec/loggable_spec.rb +17 -0
  74. data/spec/monotonic_time_spec.rb +23 -0
  75. data/spec/{notice_notifier_spec → notice_notifier}/options_spec.rb +19 -21
  76. data/spec/notice_notifier_spec.rb +20 -80
  77. data/spec/notice_spec.rb +9 -11
  78. data/spec/performance_breakdown_spec.rb +11 -0
  79. data/spec/performance_notifier_spec.rb +360 -85
  80. data/spec/query_spec.rb +11 -0
  81. data/spec/queue_spec.rb +18 -0
  82. data/spec/remote_settings/settings_data_spec.rb +365 -0
  83. data/spec/remote_settings_spec.rb +230 -0
  84. data/spec/request_spec.rb +9 -0
  85. data/spec/response_spec.rb +8 -8
  86. data/spec/spec_helper.rb +9 -13
  87. data/spec/stashable_spec.rb +23 -0
  88. data/spec/stat_spec.rb +17 -15
  89. data/spec/sync_sender_spec.rb +14 -12
  90. data/spec/tdigest_spec.rb +6 -6
  91. data/spec/thread_pool_spec.rb +187 -0
  92. data/spec/timed_trace_spec.rb +125 -0
  93. data/spec/truncator_spec.rb +12 -12
  94. metadata +55 -18
@@ -10,7 +10,7 @@ module Airbrake
10
10
  NOTIFIER = {
11
11
  name: 'airbrake-ruby'.freeze,
12
12
  version: Airbrake::AIRBRAKE_RUBY_VERSION,
13
- url: 'https://github.com/airbrake/airbrake-ruby'.freeze
13
+ url: 'https://github.com/airbrake/airbrake-ruby'.freeze,
14
14
  }.freeze
15
15
 
16
16
  ##
@@ -19,7 +19,7 @@ module Airbrake
19
19
  CONTEXT = {
20
20
  os: RUBY_PLATFORM,
21
21
  language: "#{RUBY_ENGINE}/#{RUBY_VERSION}".freeze,
22
- notifier: NOTIFIER
22
+ notifier: NOTIFIER,
23
23
  }.freeze
24
24
 
25
25
  ##
@@ -38,7 +38,7 @@ module Airbrake
38
38
  IOError,
39
39
  NotImplementedError,
40
40
  JSON::GeneratorError,
41
- Encoding::UndefinedConversionError
41
+ Encoding::UndefinedConversionError,
42
42
  ].freeze
43
43
 
44
44
  # @return [Array<Symbol>] the list of keys that can be be overwritten with
@@ -71,10 +71,10 @@ module Airbrake
71
71
  errors: NestedException.new(config, exception).as_json,
72
72
  context: context,
73
73
  environment: {
74
- program_name: $PROGRAM_NAME
74
+ program_name: $PROGRAM_NAME,
75
75
  },
76
76
  session: {},
77
- params: params
77
+ params: params,
78
78
  }
79
79
  @stash = { exception: exception }
80
80
  @truncator = Airbrake::Truncator.new(PAYLOAD_MAX_SIZE)
@@ -170,7 +170,7 @@ module Airbrake
170
170
  # Make sure we always send hostname.
171
171
  hostname: HOSTNAME,
172
172
 
173
- severity: DEFAULT_SEVERITY
173
+ severity: DEFAULT_SEVERITY,
174
174
  }.merge(CONTEXT).delete_if { |_key, val| val.nil? || val.empty? }
175
175
  end
176
176
 
@@ -187,7 +187,7 @@ module Airbrake
187
187
  @config.logger.error(
188
188
  "#{LOG_LABEL} truncation failed. File an issue at " \
189
189
  "https://github.com/airbrake/airbrake-ruby " \
190
- "and attach the following payload: #{@payload}"
190
+ "and attach the following payload: #{@payload}",
191
191
  )
192
192
  end
193
193
 
@@ -202,7 +202,7 @@ module Airbrake
202
202
  attributes = exception.to_airbrake
203
203
  rescue StandardError => ex
204
204
  @config.logger.error(
205
- "#{LOG_LABEL} #{exception.class}#to_airbrake failed: #{ex.class}: #{ex}"
205
+ "#{LOG_LABEL} #{exception.class}#to_airbrake failed: #{ex.class}: #{ex}",
206
206
  )
207
207
  end
208
208
 
@@ -213,7 +213,7 @@ module Airbrake
213
213
  rescue TypeError
214
214
  @config.logger.error(
215
215
  "#{LOG_LABEL} #{exception.class}#to_airbrake failed:" \
216
- " #{attributes} must be a Hash"
216
+ " #{attributes} must be a Hash",
217
217
  )
218
218
  end
219
219
  end
@@ -0,0 +1,17 @@
1
+ RSpec.describe Airbrake::Loggable do
2
+ describe ".instance" do
3
+ it "returns a logger" do
4
+ expect(described_class.instance).to be_a(Logger)
5
+ end
6
+ end
7
+
8
+ describe "#logger" do
9
+ let(:subject) do
10
+ Class.new { include Airbrake::Loggable }.new
11
+ end
12
+
13
+ it "returns a logger that has Logger::WARN severity" do
14
+ expect(subject.logger.level).to eq(Logger::WARN)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ RSpec.describe Airbrake::MonotonicTime do
2
+ describe ".time_in_ms" do
3
+ it "returns monotonic time in milliseconds" do
4
+ expect(subject.time_in_ms).to be_a(Float)
5
+ end
6
+
7
+ it "always returns time in the future" do
8
+ old_time = subject.time_in_ms
9
+ expect(subject.time_in_ms).to be > old_time
10
+ end
11
+ end
12
+
13
+ describe ".time_in_s" do
14
+ it "returns monotonic time in seconds" do
15
+ expect(subject.time_in_s).to be_a(Float)
16
+ end
17
+
18
+ it "always returns time in the future" do
19
+ old_time = subject.time_in_s
20
+ expect(subject.time_in_s).to be > old_time
21
+ end
22
+ end
23
+ end
@@ -1,8 +1,4 @@
1
1
  RSpec.describe Airbrake::NoticeNotifier do
2
- def expect_a_request_with_body(body)
3
- expect(a_request(:post, endpoint).with(body: body)).to have_been_made.once
4
- end
5
-
6
2
  let(:project_id) { 105138 }
7
3
  let(:project_key) { 'fd04e13d806a90f96614ad8e529b2822' }
8
4
  let(:localhost) { 'http://localhost:8080' }
@@ -19,7 +15,7 @@ RSpec.describe Airbrake::NoticeNotifier do
19
15
 
20
16
  Airbrake::Config.instance = Airbrake::Config.new(
21
17
  project_id: project_id,
22
- project_key: project_key
18
+ project_key: project_key,
23
19
  )
24
20
  end
25
21
 
@@ -67,7 +63,9 @@ RSpec.describe Airbrake::NoticeNotifier do
67
63
 
68
64
  describe ":root_directory" do
69
65
  before do
70
- Airbrake::Config.instance.merge(root_directory: '/home/kyrylo/code')
66
+ subject.add_filter(
67
+ Airbrake::Filters::RootDirectoryFilter.new('/home/kyrylo/code'),
68
+ )
71
69
  end
72
70
 
73
71
  it "filters out frames" do
@@ -75,7 +73,7 @@ RSpec.describe Airbrake::NoticeNotifier do
75
73
 
76
74
  expect(
77
75
  a_request(:post, endpoint)
78
- .with(body: %r|{"file":"/PROJECT_ROOT/airbrake/ruby/spec/airbrake_spec.+|)
76
+ .with(body: %r|{"file":"/PROJECT_ROOT/airbrake/ruby/spec/airbrake_spec.+|),
79
77
  ).to have_been_made.once
80
78
  end
81
79
 
@@ -87,7 +85,7 @@ RSpec.describe Airbrake::NoticeNotifier do
87
85
  subject.notify_sync(ex)
88
86
  expect(
89
87
  a_request(:post, endpoint)
90
- .with(body: %r{"rootDirectory":"/bingo/bango"})
88
+ .with(body: %r{"rootDirectory":"/bingo/bango"}),
91
89
  ).to have_been_made.once
92
90
  end
93
91
  end
@@ -107,7 +105,7 @@ RSpec.describe Airbrake::NoticeNotifier do
107
105
  WEBrick::HTTPServer.new(
108
106
  Port: 0,
109
107
  Logger: WEBrick::Log.new('/dev/null'),
110
- AccessLog: []
108
+ AccessLog: [],
111
109
  )
112
110
  end
113
111
 
@@ -123,7 +121,7 @@ RSpec.describe Airbrake::NoticeNotifier do
123
121
  before do
124
122
  Airbrake::Config.instance.merge(
125
123
  proxy: proxy_params,
126
- host: "http://localhost:#{proxy.config[:Port]}"
124
+ host: "http://localhost:#{proxy.config[:Port]}",
127
125
  )
128
126
 
129
127
  proxy.mount_proc '/' do |req, res|
@@ -141,7 +139,7 @@ RSpec.describe Airbrake::NoticeNotifier do
141
139
  if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.6.0")
142
140
  skip(
143
141
  "We use Webmock 2, which doesn't support Ruby 2.6+. It's " \
144
- "safe to run this test on 2.6+ once we upgrade to Webmock 3.5+"
142
+ "safe to run this test on 2.6+ once we upgrade to Webmock 3.5+",
145
143
  )
146
144
  end
147
145
  subject.notify_sync(ex)
@@ -151,10 +149,10 @@ RSpec.describe Airbrake::NoticeNotifier do
151
149
  expect(proxied_request.header['proxy-authorization'].first)
152
150
  .to eq('Basic dXNlcjpwYXNzd29yZA==')
153
151
 
154
- # rubocop:disable Metrics/LineLength
152
+ # rubocop:disable Layout/LineLength
155
153
  expect(proxied_request.request_line)
156
154
  .to eq("POST http://localhost:#{proxy.config[:Port]}/api/v3/projects/105138/notices HTTP/1.1\r\n")
157
- # rubocop:enable Metrics/LineLength
155
+ # rubocop:enable Layout/LineLength
158
156
  end
159
157
  end
160
158
 
@@ -166,7 +164,7 @@ RSpec.describe Airbrake::NoticeNotifier do
166
164
  subject.notify_sync(ex)
167
165
  expect(
168
166
  a_request(:post, endpoint)
169
- .with(body: /"context":{.*"environment":"production".*}/)
167
+ .with(body: /"context":{.*"environment":"production".*}/),
170
168
  ).to have_been_made.once
171
169
  end
172
170
  end
@@ -194,7 +192,7 @@ RSpec.describe Airbrake::NoticeNotifier do
194
192
  context "when env is set and ignore_environments doesn't mention it" do
195
193
  params = {
196
194
  environment: :development,
197
- ignore_environments: [:production]
195
+ ignore_environments: [:production],
198
196
  }
199
197
 
200
198
  include_examples 'sent notice', params
@@ -203,7 +201,7 @@ RSpec.describe Airbrake::NoticeNotifier do
203
201
  context "when the current env and notify envs are the same" do
204
202
  params = {
205
203
  environment: :development,
206
- ignore_environments: %i[production development]
204
+ ignore_environments: %i[production development],
207
205
  }
208
206
 
209
207
  include_examples 'ignored notice', params
@@ -229,21 +227,21 @@ RSpec.describe Airbrake::NoticeNotifier do
229
227
  context "when ignore_environments specifies a Regexp pattern" do
230
228
  params = {
231
229
  environment: :testing,
232
- ignore_environments: ['staging', /test.+/]
230
+ ignore_environments: ['staging', /test.+/],
233
231
  }
234
232
 
235
233
  include_examples 'ignored notice', params
236
234
  end
237
235
  end
238
236
 
239
- describe ":blacklist_keys" do
237
+ describe ":blocklist_keys" do
240
238
  # Fixes https://github.com/airbrake/airbrake-ruby/issues/276
241
- context "when specified along with :whitelist_keys" do
239
+ context "when specified along with :allowlist_keys" do
242
240
  context "and when context payload is present" do
243
241
  before do
244
242
  Airbrake::Config.instance.merge(
245
- blacklist_keys: %i[password password_confirmation],
246
- whitelist_keys: [:email, /user/i, 'account_id']
243
+ blocklist_keys: %i[password password_confirmation],
244
+ allowlist_keys: [:email, /user/i, 'account_id'],
247
245
  )
248
246
  end
249
247
 
@@ -4,7 +4,7 @@ RSpec.describe Airbrake::NoticeNotifier do
4
4
  project_id: 1,
5
5
  project_key: 'abc',
6
6
  logger: Logger.new('/dev/null'),
7
- performance_stats: true
7
+ performance_stats: true,
8
8
  )
9
9
  end
10
10
 
@@ -23,62 +23,6 @@ RSpec.describe Airbrake::NoticeNotifier do
23
23
  .with(instance_of(Airbrake::Filters::ExceptionAttributesFilter))
24
24
  subject
25
25
  end
26
-
27
- context "when user config has some whitelist keys" do
28
- before { Airbrake::Config.instance.merge(whitelist_keys: %w[foo]) }
29
-
30
- it "appends the whitelist filter" do
31
- expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
32
- .with(instance_of(Airbrake::Filters::KeysWhitelist))
33
- subject
34
- end
35
- end
36
-
37
- context "when user config doesn't have any whitelist keys" do
38
- it "doesn't append the whitelist filter" do
39
- expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
40
- .with(instance_of(Airbrake::Filters::KeysWhitelist))
41
- subject
42
- end
43
- end
44
-
45
- context "when user config has some blacklist keys" do
46
- before { Airbrake::Config.instance.merge(blacklist_keys: %w[bar]) }
47
-
48
- it "appends the blacklist filter" do
49
- expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
50
- .with(instance_of(Airbrake::Filters::KeysBlacklist))
51
- subject
52
- end
53
- end
54
-
55
- context "when user config doesn't have any blacklist keys" do
56
- it "doesn't append the blacklist filter" do
57
- expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
58
- .with(instance_of(Airbrake::Filters::KeysBlacklist))
59
- subject
60
- end
61
- end
62
-
63
- context "when user config specifies a root directory" do
64
- before { Airbrake::Config.instance.merge(root_directory: '/foo') }
65
-
66
- it "appends the root directory filter" do
67
- expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
68
- .with(instance_of(Airbrake::Filters::RootDirectoryFilter))
69
- subject
70
- end
71
- end
72
-
73
- context "when user config doesn't specify a root directory" do
74
- it "doesn't append the root directory filter" do
75
- expect_any_instance_of(Airbrake::Config).to receive(:root_directory)
76
- .and_return(nil)
77
- expect_any_instance_of(Airbrake::FilterChain).not_to receive(:add_filter)
78
- .with(instance_of(Airbrake::Filters::RootDirectoryFilter))
79
- subject
80
- end
81
- end
82
26
  end
83
27
  end
84
28
 
@@ -88,7 +32,7 @@ RSpec.describe Airbrake::NoticeNotifier do
88
32
  let(:body) do
89
33
  {
90
34
  'id' => '00054414-b147-6ffa-85d6-1524d83362a6',
91
- 'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6'
35
+ 'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6',
92
36
  }.to_json
93
37
  end
94
38
 
@@ -166,7 +110,7 @@ RSpec.describe Airbrake::NoticeNotifier do
166
110
  before do
167
111
  Airbrake::Config.instance.merge(
168
112
  environment: 'test',
169
- ignore_environments: %w[test]
113
+ ignore_environments: %w[test],
170
114
  )
171
115
  end
172
116
 
@@ -185,14 +129,10 @@ RSpec.describe Airbrake::NoticeNotifier do
185
129
  describe "#notify_sync" do
186
130
  let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/1/notices' }
187
131
 
188
- let(:user_params) do
189
- { project_id: 1, project_key: 'abc', logger: Logger.new('/dev/null') }
190
- end
191
-
192
132
  let(:body) do
193
133
  {
194
134
  'id' => '00054414-b147-6ffa-85d6-1524d83362a6',
195
- 'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6'
135
+ 'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6',
196
136
  }
197
137
  end
198
138
 
@@ -213,8 +153,8 @@ RSpec.describe Airbrake::NoticeNotifier do
213
153
  subject.notify_sync('foo', bingo: 'bango')
214
154
  expect(
215
155
  a_request(:post, endpoint).with(
216
- body: /"params":{.*"bingo":"bango".*}/
217
- )
156
+ body: /"params":{.*"bingo":"bango".*}/,
157
+ ),
218
158
  ).to have_been_made.once
219
159
  end
220
160
 
@@ -250,7 +190,7 @@ RSpec.describe Airbrake::NoticeNotifier do
250
190
  context "when the provided environment is ignored" do
251
191
  before do
252
192
  Airbrake::Config.instance.merge(
253
- environment: 'test', ignore_environments: %w[test]
193
+ environment: 'test', ignore_environments: %w[test],
254
194
  )
255
195
  end
256
196
 
@@ -316,7 +256,7 @@ RSpec.describe Airbrake::NoticeNotifier do
316
256
  it "returns the full generated backtrace" do
317
257
  backtrace = [
318
258
  "/lib/airbrake-ruby/a.rb:84:in `build_notice'",
319
- "/lib/airbrake-ruby/b.rb:124:in `send_notice'"
259
+ "/lib/airbrake-ruby/b.rb:124:in `send_notice'",
320
260
  ]
321
261
  allow(Kernel).to receive(:caller).and_return(backtrace)
322
262
 
@@ -325,8 +265,8 @@ RSpec.describe Airbrake::NoticeNotifier do
325
265
  expect(notice[:errors].first[:backtrace]).to eq(
326
266
  [
327
267
  { file: '/lib/airbrake-ruby/a.rb', line: 84, function: 'build_notice' },
328
- { file: '/lib/airbrake-ruby/b.rb', line: 124, function: 'send_notice' }
329
- ]
268
+ { file: '/lib/airbrake-ruby/b.rb', line: 124, function: 'send_notice' },
269
+ ],
330
270
  )
331
271
  end
332
272
  end
@@ -336,7 +276,7 @@ RSpec.describe Airbrake::NoticeNotifier do
336
276
  backtrace = [
337
277
  "/airbrake-ruby/lib/airbrake-ruby/a.rb:84:in `b'",
338
278
  "/airbrake-ruby/lib/foo/b.rb:84:in `build'",
339
- "/airbrake-ruby/lib/bar/c.rb:124:in `send'"
279
+ "/airbrake-ruby/lib/bar/c.rb:124:in `send'",
340
280
  ]
341
281
  allow(Kernel).to receive(:caller).and_return(backtrace)
342
282
 
@@ -345,8 +285,8 @@ RSpec.describe Airbrake::NoticeNotifier do
345
285
  expect(notice[:errors].first[:backtrace]).to eq(
346
286
  [
347
287
  { file: '/airbrake-ruby/lib/foo/b.rb', line: 84, function: 'build' },
348
- { file: '/airbrake-ruby/lib/bar/c.rb', line: 124, function: 'send' }
349
- ]
288
+ { file: '/airbrake-ruby/lib/bar/c.rb', line: 124, function: 'send' },
289
+ ],
350
290
  )
351
291
  end
352
292
  end
@@ -363,21 +303,21 @@ RSpec.describe Airbrake::NoticeNotifier do
363
303
  backtrace = [
364
304
  "org/jruby/RubyKernel.java:998:in `eval'",
365
305
  "/ruby/stdlib/irb/workspace.rb:87:in `evaluate'",
366
- "/ruby/stdlib/irb.rb:489:in `block in eval_input'"
306
+ "/ruby/stdlib/irb.rb:489:in `block in eval_input'",
367
307
  ]
368
308
  allow(Kernel).to receive(:caller).and_return(backtrace)
369
309
 
370
310
  notice = subject.build_notice(Exception.new)
371
311
 
372
- # rubocop:disable Metrics/LineLength
312
+ # rubocop:disable Layout/LineLength
373
313
  expect(notice[:errors].first[:backtrace]).to eq(
374
314
  [
375
315
  { file: 'org/jruby/RubyKernel.java', line: 998, function: 'eval' },
376
316
  { file: '/ruby/stdlib/irb/workspace.rb', line: 87, function: 'evaluate' },
377
- { file: '/ruby/stdlib/irb.rb:489', line: 489, function: 'block in eval_input' }
378
- ]
317
+ { file: '/ruby/stdlib/irb.rb:489', line: 489, function: 'block in eval_input' },
318
+ ],
379
319
  )
380
- # rubocop:enable Metrics/LineLength
320
+ # rubocop:enable Layout/LineLength
381
321
  end
382
322
  end
383
323
 
@@ -388,9 +328,9 @@ RSpec.describe Airbrake::NoticeNotifier do
388
328
  end
389
329
 
390
330
  it "raises error" do
391
- expect { subject.build_notice(Exception.new) }.to raise_error(
331
+ expect { subject.build_notice(Exception.new('oops')) }.to raise_error(
392
332
  Airbrake::Error,
393
- 'attempted to build Exception with closed Airbrake instance'
333
+ "Airbrake is closed; can't build exception: Exception: oops",
394
334
  )
395
335
  end
396
336
  end
data/spec/notice_spec.rb CHANGED
@@ -17,7 +17,7 @@ RSpec.describe Airbrake::Notice do
17
17
  before do
18
18
  Airbrake::Config.instance.merge(
19
19
  app_version: "1.2.3",
20
- root_directory: "/one/two"
20
+ root_directory: "/one/two",
21
21
  )
22
22
  end
23
23
 
@@ -34,7 +34,7 @@ RSpec.describe Airbrake::Notice do
34
34
  context "when versions is empty" do
35
35
  it "doesn't set the 'versions' payload" do
36
36
  expect(notice.to_json).not_to match(
37
- /"context":{"versions":{"dep":"1.2.3"}}/
37
+ /"context":{"versions":{"dep":"1.2.3"}}/,
38
38
  )
39
39
  end
40
40
  end
@@ -43,7 +43,7 @@ RSpec.describe Airbrake::Notice do
43
43
  it "sets the 'versions' payload" do
44
44
  notice[:context][:versions] = { 'dep' => '1.2.3' }
45
45
  expect(notice.to_json).to match(
46
- /"context":{.*"versions":{"dep":"1.2.3"}.*}/
46
+ /"context":{.*"versions":{"dep":"1.2.3"}.*}/,
47
47
  )
48
48
  end
49
49
  end
@@ -192,7 +192,7 @@ RSpec.describe Airbrake::Notice do
192
192
  it "doesn't fail" do
193
193
  notice[:params] = { a: { b: { c: ObjectWithIoIvars.new } } }
194
194
  expect(notice.to_json).to match(
195
- /"params":{"a":{"b":{"c":".+ObjectWithIoIvars.+"}}.*}/
195
+ /"params":{"a":{"b":{"c":".+ObjectWithIoIvars.+"}}.*}/,
196
196
  )
197
197
  end
198
198
  end
@@ -201,7 +201,7 @@ RSpec.describe Airbrake::Notice do
201
201
  it "doesn't fail" do
202
202
  notice[:params] = { a: [[ObjectWithIoIvars.new]] }
203
203
  expect(notice.to_json).to match(
204
- /"params":{"a":\[\[".+ObjectWithIoIvars.+"\]\].*}/
204
+ /"params":{"a":\[\[".+ObjectWithIoIvars.+"\]\].*}/,
205
205
  )
206
206
  end
207
207
  end
@@ -268,7 +268,7 @@ RSpec.describe Airbrake::Notice do
268
268
  it "sets a payload value" do
269
269
  hash = { bingo: 'bango' }
270
270
  notice[:params] = hash
271
- expect(notice[:params]).to equal(hash)
271
+ expect(notice[:params]).to eq(hash)
272
272
  end
273
273
 
274
274
  it "raises error if notice is ignored" do
@@ -289,10 +289,8 @@ RSpec.describe Airbrake::Notice do
289
289
  end
290
290
 
291
291
  describe "#stash" do
292
- it "returns a hash" do
293
- obj = Object.new
294
- notice.stash[:bingo_object] = obj
295
- expect(notice.stash[:bingo_object]).to eql(obj)
296
- end
292
+ subject { described_class.new(AirbrakeTestError.new) }
293
+
294
+ it { is_expected.to respond_to(:stash) }
297
295
  end
298
296
  end
@@ -0,0 +1,11 @@
1
+ RSpec.describe Airbrake::PerformanceBreakdown do
2
+ describe "#stash" do
3
+ subject do
4
+ described_class.new(
5
+ method: 'GET', route: '/', response_type: '', groups: {},
6
+ )
7
+ end
8
+
9
+ it { is_expected.to respond_to(:stash) }
10
+ end
11
+ end