airbrake-ruby 4.1.0 → 5.0.0

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