airbrake-ruby 5.0.1 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +4 -2
  3. data/lib/airbrake-ruby/async_sender.rb +3 -1
  4. data/lib/airbrake-ruby/config.rb +15 -6
  5. data/lib/airbrake-ruby/config/processor.rb +7 -20
  6. data/lib/airbrake-ruby/context.rb +51 -0
  7. data/lib/airbrake-ruby/file_cache.rb +1 -1
  8. data/lib/airbrake-ruby/filter_chain.rb +2 -0
  9. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  10. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  11. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
  12. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
  15. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -3
  16. data/lib/airbrake-ruby/grouppable.rb +1 -1
  17. data/lib/airbrake-ruby/ignorable.rb +0 -2
  18. data/lib/airbrake-ruby/mergeable.rb +1 -1
  19. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  20. data/lib/airbrake-ruby/performance_notifier.rb +1 -2
  21. data/lib/airbrake-ruby/remote_settings.rb +10 -50
  22. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  23. data/lib/airbrake-ruby/remote_settings/settings_data.rb +3 -8
  24. data/lib/airbrake-ruby/tdigest.rb +7 -6
  25. data/lib/airbrake-ruby/thread_pool.rb +5 -3
  26. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  27. data/lib/airbrake-ruby/version.rb +2 -2
  28. data/spec/airbrake_spec.rb +139 -76
  29. data/spec/async_sender_spec.rb +10 -8
  30. data/spec/backtrace_spec.rb +13 -10
  31. data/spec/benchmark_spec.rb +5 -3
  32. data/spec/code_hunk_spec.rb +24 -15
  33. data/spec/config/processor_spec.rb +29 -87
  34. data/spec/config/validator_spec.rb +5 -2
  35. data/spec/config_spec.rb +26 -17
  36. data/spec/context_spec.rb +54 -0
  37. data/spec/deploy_notifier_spec.rb +6 -4
  38. data/spec/file_cache_spec.rb +1 -0
  39. data/spec/filter_chain_spec.rb +29 -24
  40. data/spec/filters/context_filter_spec.rb +14 -5
  41. data/spec/filters/dependency_filter_spec.rb +3 -1
  42. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  43. data/spec/filters/gem_root_filter_spec.rb +5 -2
  44. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  45. data/spec/filters/git_repository_filter.rb +9 -9
  46. data/spec/filters/git_revision_filter_spec.rb +19 -19
  47. data/spec/filters/keys_allowlist_spec.rb +25 -16
  48. data/spec/filters/keys_blocklist_spec.rb +25 -18
  49. data/spec/filters/root_directory_filter_spec.rb +3 -3
  50. data/spec/filters/sql_filter_spec.rb +26 -26
  51. data/spec/filters/system_exit_filter_spec.rb +4 -2
  52. data/spec/filters/thread_filter_spec.rb +16 -14
  53. data/spec/loggable_spec.rb +2 -2
  54. data/spec/monotonic_time_spec.rb +8 -6
  55. data/spec/nested_exception_spec.rb +46 -46
  56. data/spec/notice_notifier/options_spec.rb +23 -13
  57. data/spec/notice_notifier_spec.rb +52 -47
  58. data/spec/notice_spec.rb +6 -2
  59. data/spec/performance_notifier_spec.rb +67 -60
  60. data/spec/promise_spec.rb +38 -32
  61. data/spec/remote_settings/callback_spec.rb +162 -0
  62. data/spec/remote_settings/settings_data_spec.rb +23 -53
  63. data/spec/remote_settings_spec.rb +42 -75
  64. data/spec/response_spec.rb +34 -12
  65. data/spec/stashable_spec.rb +5 -5
  66. data/spec/stat_spec.rb +7 -5
  67. data/spec/sync_sender_spec.rb +49 -16
  68. data/spec/tdigest_spec.rb +61 -56
  69. data/spec/thread_pool_spec.rb +65 -55
  70. data/spec/time_truncate_spec.rb +4 -2
  71. data/spec/timed_trace_spec.rb +32 -30
  72. data/spec/truncator_spec.rb +72 -43
  73. metadata +53 -47
@@ -0,0 +1,44 @@
1
+ module Airbrake
2
+ class RemoteSettings
3
+ # Callback is a class that provides a callback for the config poller, which
4
+ # updates the local config according to the data.
5
+ #
6
+ # @api private
7
+ # @since v5.0.2
8
+ class Callback
9
+ def initialize(config)
10
+ @config = config
11
+ @orig_error_notifications = config.error_notifications
12
+ @orig_performance_stats = config.performance_stats
13
+ end
14
+
15
+ # @param [Airbrake::RemoteSettings::SettingsData] data
16
+ # @return [void]
17
+ def call(data)
18
+ @config.logger.debug do
19
+ "#{LOG_LABEL} applying remote settings: #{data.to_h}"
20
+ end
21
+
22
+ @config.error_host = data.error_host if data.error_host
23
+ @config.apm_host = data.apm_host if data.apm_host
24
+
25
+ process_error_notifications(data)
26
+ process_performance_stats(data)
27
+ end
28
+
29
+ private
30
+
31
+ def process_error_notifications(data)
32
+ return unless @orig_error_notifications
33
+
34
+ @config.error_notifications = data.error_notifications?
35
+ end
36
+
37
+ def process_performance_stats(data)
38
+ return unless @orig_performance_stats
39
+
40
+ @config.performance_stats = data.performance_stats?
41
+ end
42
+ end
43
+ end
44
+ end
@@ -11,7 +11,7 @@ module Airbrake
11
11
  #
12
12
  # settings_data.interval #=> 600
13
13
  #
14
- # @since 5.0.0
14
+ # @since v5.0.0
15
15
  # @api private
16
16
  class SettingsData
17
17
  # @return [Integer] how frequently we should poll the config API
@@ -58,13 +58,8 @@ module Airbrake
58
58
  # @param [String] remote_config_host
59
59
  # @return [String] where the config is stored on S3.
60
60
  def config_route(remote_config_host)
61
- if @data.key?('config_route') &&
62
- @data['config_route'] && !@data['config_route'].empty?
63
- return format(
64
- CONFIG_ROUTE_PATTERN,
65
- host: @data['config_route'].chomp('/'),
66
- project_id: @project_id,
67
- )
61
+ if @data['config_route'] && !@data['config_route'].empty?
62
+ return "#{remote_config_host.chomp('/')}/#{@data['config_route']}"
68
63
  end
69
64
 
70
65
  format(
@@ -24,6 +24,7 @@ module Airbrake
24
24
  # @since v3.2.0
25
25
  class Centroid
26
26
  attr_accessor :mean, :n, :cumn, :mean_cumn
27
+
27
28
  def initialize(mean, n, cumn, mean_cumn = nil)
28
29
  @mean = mean
29
30
  @n = n
@@ -130,7 +131,7 @@ module Airbrake
130
131
  points = to_a
131
132
  reset!
132
133
  push_centroid(points.shuffle)
133
- _cumulate(true, true)
134
+ _cumulate(exact: true, force: true)
134
135
  nil
135
136
  end
136
137
 
@@ -175,7 +176,7 @@ module Airbrake
175
176
  elsif item > max[1].mean
176
177
  1.0
177
178
  else
178
- _cumulate(true)
179
+ _cumulate(exact: true)
179
180
  bound = bound_mean(item)
180
181
  lower, upper = bound
181
182
  mean_cumn = lower.mean_cumn
@@ -204,7 +205,7 @@ module Airbrake
204
205
  if size == 0
205
206
  nil
206
207
  else
207
- _cumulate(true)
208
+ _cumulate(exact: true)
208
209
  h = @size * item
209
210
  lower, upper = bound_mean_cumn(h)
210
211
  if lower.nil? && upper.nil?
@@ -306,7 +307,7 @@ module Airbrake
306
307
  centroid.mean += n * (x - centroid.mean) / (centroid.n + n)
307
308
  end
308
309
 
309
- _cumulate(false, true) if centroid.mean_cumn.nil?
310
+ _cumulate(exact: false, force: true) if centroid.mean_cumn.nil?
310
311
 
311
312
  centroid.cumn += n
312
313
  centroid.mean_cumn += n / 2.0
@@ -314,7 +315,7 @@ module Airbrake
314
315
  end
315
316
 
316
317
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
317
- def _cumulate(exact = false, force = false)
318
+ def _cumulate(exact: false, force: false)
318
319
  unless force
319
320
  factor = if @last_cumulate == 0
320
321
  Float::INFINITY
@@ -361,7 +362,7 @@ module Airbrake
361
362
  end
362
363
  end
363
364
 
364
- _cumulate(false)
365
+ _cumulate(exact: false)
365
366
 
366
367
  # If the number of centroids has grown to a very large size,
367
368
  # it may be due to values being inserted in sorted order.
@@ -6,6 +6,7 @@ module Airbrake
6
6
  # # Initialize a new thread pool with 5 workers and a queue size of 100. Set
7
7
  # # the block to be run concurrently.
8
8
  # thread_pool = ThreadPool.new(
9
+ # name: 'performance-notifier',
9
10
  # worker_size: 5,
10
11
  # queue_size: 100,
11
12
  # block: proc { |message| print "ECHO: #{message}..."}
@@ -24,7 +25,8 @@ module Airbrake
24
25
  # @note This is exposed for eaiser unit testing
25
26
  attr_reader :workers
26
27
 
27
- def initialize(worker_size:, queue_size:, block:)
28
+ def initialize(worker_size:, queue_size:, block:, name: nil)
29
+ @name = name
28
30
  @worker_size = worker_size
29
31
  @queue_size = queue_size
30
32
  @block = block
@@ -102,7 +104,7 @@ module Airbrake
102
104
 
103
105
  unless @queue.empty?
104
106
  msg = "#{LOG_LABEL} waiting to process #{@queue.size} task(s)..."
105
- logger.debug(msg + ' (Ctrl-C to abort)')
107
+ logger.debug("#{msg} (Ctrl-C to abort)")
106
108
  end
107
109
 
108
110
  @worker_size.times { @queue << :stop }
@@ -111,7 +113,7 @@ module Airbrake
111
113
  end
112
114
 
113
115
  threads.each(&:join)
114
- logger.debug("#{LOG_LABEL} thread pool closed")
116
+ logger.debug("#{LOG_LABEL} #{@name} thread pool closed")
115
117
  end
116
118
 
117
119
  def closed?
@@ -50,9 +50,7 @@ module Airbrake
50
50
 
51
51
  # @return [Hash<String=>Float>]
52
52
  def spans
53
- @spans.each_with_object({}) do |(label, benchmark), new_spans|
54
- new_spans[label] = benchmark.duration
55
- end
53
+ @spans.transform_values(&:duration)
56
54
  end
57
55
  end
58
56
  end
@@ -3,10 +3,10 @@
3
3
  module Airbrake
4
4
  # @return [String] the library version
5
5
  # @api public
6
- AIRBRAKE_RUBY_VERSION = '5.0.1'.freeze
6
+ AIRBRAKE_RUBY_VERSION = '5.2.1'.freeze
7
7
 
8
8
  # @return [Hash{Symbol=>String}] the information about the notifier library
9
- # @since 5.0.0
9
+ # @since v5.0.0
10
10
  # @api public
11
11
  NOTIFIER_INFO = {
12
12
  name: 'airbrake-ruby'.freeze,
@@ -30,11 +30,9 @@ RSpec.describe Airbrake do
30
30
 
31
31
  it "yields the config" do
32
32
  expect do |b|
33
- begin
34
- described_class.configure(&b)
35
- rescue Airbrake::Error
36
- nil
37
- end
33
+ described_class.configure(&b)
34
+ rescue Airbrake::Error
35
+ nil
38
36
  end.to yield_with_args(Airbrake::Config)
39
37
  end
40
38
 
@@ -62,26 +60,26 @@ RSpec.describe Airbrake do
62
60
 
63
61
  context "when called multiple times" do
64
62
  it "doesn't overwrite performance notifier" do
65
- described_class.configure {}
63
+ described_class.configure { anything }
66
64
  performance_notifier = described_class.performance_notifier
67
65
 
68
- described_class.configure {}
66
+ described_class.configure { anything }
69
67
  expect(described_class.performance_notifier).to eql(performance_notifier)
70
68
  end
71
69
 
72
70
  it "doesn't overwrite notice notifier" do
73
- described_class.configure {}
71
+ described_class.configure { anything }
74
72
  notice_notifier = described_class.notice_notifier
75
73
 
76
- described_class.configure {}
74
+ described_class.configure { anything }
77
75
  expect(described_class.notice_notifier).to eql(notice_notifier)
78
76
  end
79
77
 
80
78
  it "doesn't overwrite deploy notifier" do
81
- described_class.configure {}
79
+ described_class.configure { anything }
82
80
  deploy_notifier = described_class.deploy_notifier
83
81
 
84
- described_class.configure {}
82
+ described_class.configure { anything }
85
83
  expect(described_class.deploy_notifier).to eql(deploy_notifier)
86
84
  end
87
85
 
@@ -91,20 +89,24 @@ RSpec.describe Airbrake do
91
89
  c.project_key = '2'
92
90
  end
93
91
 
94
- expect(described_class.notice_notifier).not_to receive(:add_filter)
95
- 10.times { described_class.configure {} }
92
+ allow(described_class.notice_notifier).to receive(:add_filter)
93
+
94
+ 10.times { described_class.configure { anything } }
95
+
96
+ expect(described_class.notice_notifier).not_to have_received(:add_filter)
96
97
  end
97
98
 
98
99
  it "appends some default filters" do
99
100
  allow(described_class.notice_notifier).to receive(:add_filter)
100
- expect(described_class.notice_notifier).to receive(:add_filter).with(
101
- an_instance_of(Airbrake::Filters::RootDirectoryFilter),
102
- )
103
101
 
104
102
  described_class.configure do |c|
105
103
  c.project_id = 1
106
104
  c.project_key = '2'
107
105
  end
106
+
107
+ expect(described_class.notice_notifier).to have_received(:add_filter).with(
108
+ an_instance_of(Airbrake::Filters::RootDirectoryFilter),
109
+ )
108
110
  end
109
111
  end
110
112
 
@@ -112,14 +114,21 @@ RSpec.describe Airbrake do
112
114
  before { allow(described_class.notice_notifier).to receive(:add_filter) }
113
115
 
114
116
  it "adds blocklist filter" do
115
- expect(described_class.notice_notifier).to receive(:add_filter)
116
- .with(an_instance_of(Airbrake::Filters::KeysBlocklist))
117
+ allow(described_class.notice_notifier).to receive(:add_filter)
118
+
117
119
  described_class.configure { |c| c.blocklist_keys = %w[password] }
120
+
121
+ expect(described_class.notice_notifier).to have_received(:add_filter)
122
+ .with(an_instance_of(Airbrake::Filters::KeysBlocklist))
118
123
  end
119
124
 
120
125
  it "initializes blocklist with specified parameters" do
121
- expect(Airbrake::Filters::KeysBlocklist).to receive(:new).with(%w[password])
126
+ allow(Airbrake::Filters::KeysBlocklist).to receive(:new)
127
+
122
128
  described_class.configure { |c| c.blocklist_keys = %w[password] }
129
+
130
+ expect(Airbrake::Filters::KeysBlocklist)
131
+ .to have_received(:new).with(%w[password])
123
132
  end
124
133
  end
125
134
 
@@ -127,14 +136,17 @@ RSpec.describe Airbrake do
127
136
  before { allow(described_class.notice_notifier).to receive(:add_filter) }
128
137
 
129
138
  it "adds allowlist filter" do
130
- expect(described_class.notice_notifier).to receive(:add_filter)
131
- .with(an_instance_of(Airbrake::Filters::KeysAllowlist))
132
139
  described_class.configure { |c| c.allowlist_keys = %w[banana] }
140
+ expect(described_class.notice_notifier).to have_received(:add_filter)
141
+ .with(an_instance_of(Airbrake::Filters::KeysAllowlist))
133
142
  end
134
143
 
135
144
  it "initializes allowlist with specified parameters" do
136
- expect(Airbrake::Filters::KeysAllowlist).to receive(:new).with(%w[banana])
145
+ allow(Airbrake::Filters::KeysAllowlist).to receive(:new)
146
+
137
147
  described_class.configure { |c| c.allowlist_keys = %w[banana] }
148
+ expect(Airbrake::Filters::KeysAllowlist)
149
+ .to have_received(:new).with(%w[banana])
138
150
  end
139
151
  end
140
152
 
@@ -142,77 +154,90 @@ RSpec.describe Airbrake do
142
154
  before { allow(described_class.notice_notifier).to receive(:add_filter) }
143
155
 
144
156
  it "adds root directory filter" do
145
- expect(described_class.notice_notifier).to receive(:add_filter)
146
- .with(an_instance_of(Airbrake::Filters::RootDirectoryFilter))
147
157
  described_class.configure { |c| c.root_directory = '/my/path' }
158
+
159
+ expect(described_class.notice_notifier).to have_received(:add_filter)
160
+ .with(an_instance_of(Airbrake::Filters::RootDirectoryFilter))
148
161
  end
149
162
 
150
163
  it "initializes root directory filter with specified path" do
151
- expect(Airbrake::Filters::RootDirectoryFilter)
152
- .to receive(:new).with('/my/path')
164
+ allow(Airbrake::Filters::RootDirectoryFilter).to receive(:new)
153
165
  described_class.configure { |c| c.root_directory = '/my/path' }
166
+
167
+ expect(Airbrake::Filters::RootDirectoryFilter)
168
+ .to have_received(:new).with('/my/path')
154
169
  end
155
170
 
156
171
  it "adds git revision filter" do
157
- expect(described_class.notice_notifier).to receive(:add_filter)
158
- .with(an_instance_of(Airbrake::Filters::GitRevisionFilter))
159
172
  described_class.configure { |c| c.root_directory = '/my/path' }
173
+ expect(described_class.notice_notifier).to have_received(:add_filter)
174
+ .with(an_instance_of(Airbrake::Filters::GitRevisionFilter))
160
175
  end
161
176
 
162
177
  it "initializes git revision filter with correct root directory" do
163
- expect(Airbrake::Filters::GitRevisionFilter)
164
- .to receive(:new).with('/my/path')
178
+ allow(Airbrake::Filters::GitRevisionFilter).to receive(:new)
165
179
  described_class.configure { |c| c.root_directory = '/my/path' }
180
+
181
+ expect(Airbrake::Filters::GitRevisionFilter)
182
+ .to have_received(:new).with('/my/path')
166
183
  end
167
184
 
168
185
  it "adds git repository filter" do
169
- expect(described_class.notice_notifier).to receive(:add_filter)
170
- .with(an_instance_of(Airbrake::Filters::GitRepositoryFilter))
171
186
  described_class.configure { |c| c.root_directory = '/my/path' }
187
+
188
+ expect(described_class.notice_notifier).to have_received(:add_filter)
189
+ .with(an_instance_of(Airbrake::Filters::GitRepositoryFilter))
172
190
  end
173
191
 
174
192
  it "initializes git repository filter with correct root directory" do
175
- expect(Airbrake::Filters::GitRepositoryFilter)
176
- .to receive(:new).with('/my/path')
193
+ allow(Airbrake::Filters::GitRepositoryFilter).to receive(:new)
194
+
177
195
  described_class.configure { |c| c.root_directory = '/my/path' }
196
+
197
+ expect(Airbrake::Filters::GitRepositoryFilter)
198
+ .to have_received(:new).with('/my/path')
178
199
  end
179
200
 
180
201
  it "adds git last checkout filter" do
181
- expect(described_class.notice_notifier).to receive(:add_filter)
182
- .with(an_instance_of(Airbrake::Filters::GitLastCheckoutFilter))
183
202
  described_class.configure { |c| c.root_directory = '/my/path' }
203
+ expect(described_class.notice_notifier).to have_received(:add_filter)
204
+ .with(an_instance_of(Airbrake::Filters::GitLastCheckoutFilter))
184
205
  end
185
206
 
186
207
  it "initializes git last checkout filter with correct root directory" do
187
- expect(Airbrake::Filters::GitLastCheckoutFilter)
188
- .to receive(:new).with('/my/path')
208
+ allow(Airbrake::Filters::GitLastCheckoutFilter).to receive(:new)
189
209
  described_class.configure { |c| c.root_directory = '/my/path' }
210
+
211
+ expect(Airbrake::Filters::GitLastCheckoutFilter)
212
+ .to have_received(:new).with('/my/path')
190
213
  end
191
214
  end
192
215
  end
193
216
 
194
217
  describe ".notify_request" do
218
+ before do
219
+ allow(described_class.performance_notifier).to receive(:notify)
220
+ end
221
+
195
222
  context "when :stash key is not provided" do
196
223
  it "doesn't add anything to the stash of the request" do
197
- expect(described_class.performance_notifier).to receive(:notify) do |request|
198
- expect(request.stash).to be_empty
199
- end
200
-
201
224
  described_class.notify_request(
202
225
  method: 'GET',
203
226
  route: '/',
204
227
  status_code: 200,
205
228
  timing: 1,
206
229
  )
230
+
231
+ expect(
232
+ described_class.performance_notifier,
233
+ ).to have_received(:notify) do |request|
234
+ expect(request.stash).to be_empty
235
+ end
207
236
  end
208
237
  end
209
238
 
210
239
  context "when :stash key is provided" do
211
240
  it "adds the value as the stash of the request" do
212
- expect(described_class.performance_notifier).to receive(:notify) do |request|
213
- expect(request.stash).to eq(request_id: 1)
214
- end
215
-
216
241
  described_class.notify_request(
217
242
  {
218
243
  method: 'GET',
@@ -222,13 +247,19 @@ RSpec.describe Airbrake do
222
247
  },
223
248
  request_id: 1,
224
249
  )
250
+
251
+ expect(
252
+ described_class.performance_notifier,
253
+ ).to have_received(:notify) do |request|
254
+ expect(request.stash).to eq(request_id: 1)
255
+ end
225
256
  end
226
257
  end
227
258
  end
228
259
 
229
260
  describe ".notify_request_sync" do
230
261
  it "notifies request synchronously" do
231
- expect(described_class.performance_notifier).to receive(:notify_sync)
262
+ allow(described_class.performance_notifier).to receive(:notify_sync)
232
263
 
233
264
  described_class.notify_request_sync(
234
265
  {
@@ -239,31 +270,35 @@ RSpec.describe Airbrake do
239
270
  },
240
271
  request_id: 1,
241
272
  )
273
+
274
+ expect(described_class.performance_notifier).to have_received(:notify_sync)
242
275
  end
243
276
  end
244
277
 
245
278
  describe ".notify_query" do
279
+ before do
280
+ allow(described_class.performance_notifier).to receive(:notify)
281
+ end
282
+
246
283
  context "when :stash key is not provided" do
247
284
  it "doesn't add anything to the stash of the query" do
248
- expect(described_class.performance_notifier).to receive(:notify) do |query|
249
- expect(query.stash).to be_empty
250
- end
251
-
252
285
  described_class.notify_query(
253
286
  method: 'GET',
254
287
  route: '/',
255
288
  query: '',
256
289
  timing: 1,
257
290
  )
291
+
292
+ expect(
293
+ described_class.performance_notifier,
294
+ ).to have_received(:notify) do |query|
295
+ expect(query.stash).to be_empty
296
+ end
258
297
  end
259
298
  end
260
299
 
261
300
  context "when :stash key is provided" do
262
301
  it "adds the value as the stash of the query" do
263
- expect(described_class.performance_notifier).to receive(:notify) do |query|
264
- expect(query.stash).to eq(request_id: 1)
265
- end
266
-
267
302
  described_class.notify_query(
268
303
  {
269
304
  method: 'GET',
@@ -273,13 +308,19 @@ RSpec.describe Airbrake do
273
308
  },
274
309
  request_id: 1,
275
310
  )
311
+
312
+ expect(
313
+ described_class.performance_notifier,
314
+ ).to have_received(:notify) do |query|
315
+ expect(query.stash).to eq(request_id: 1)
316
+ end
276
317
  end
277
318
  end
278
319
  end
279
320
 
280
321
  describe ".notify_query_sync" do
281
322
  it "notifies query synchronously" do
282
- expect(described_class.performance_notifier).to receive(:notify_sync)
323
+ allow(described_class.performance_notifier).to receive(:notify_sync)
283
324
 
284
325
  described_class.notify_query_sync(
285
326
  {
@@ -290,33 +331,35 @@ RSpec.describe Airbrake do
290
331
  },
291
332
  request_id: 1,
292
333
  )
334
+
335
+ expect(described_class.performance_notifier).to have_received(:notify_sync)
293
336
  end
294
337
  end
295
338
 
296
339
  describe ".notify_performance_breakdown" do
340
+ before do
341
+ allow(described_class.performance_notifier).to receive(:notify)
342
+ end
343
+
297
344
  context "when :stash key is not provided" do
298
345
  it "doesn't add anything to the stash of the performance breakdown" do
299
- expect(described_class.performance_notifier).to receive(:notify) do |query|
300
- expect(query.stash).to be_empty
301
- end
302
-
303
346
  described_class.notify_query(
304
347
  method: 'GET',
305
348
  route: '/',
306
349
  query: '',
307
350
  timing: 1,
308
351
  )
309
- end
310
- end
311
352
 
312
- context "when :stash key is provided" do
313
- it "adds the value as the stash of the performance breakdown" do
314
353
  expect(
315
354
  described_class.performance_notifier,
316
- ).to receive(:notify) do |performance_breakdown|
317
- expect(performance_breakdown.stash).to eq(request_id: 1)
355
+ ).to have_received(:notify) do |query|
356
+ expect(query.stash).to be_empty
318
357
  end
358
+ end
359
+ end
319
360
 
361
+ context "when :stash key is provided" do
362
+ it "adds the value as the stash of the performance breakdown" do
320
363
  described_class.notify_performance_breakdown(
321
364
  {
322
365
  method: 'GET',
@@ -327,13 +370,19 @@ RSpec.describe Airbrake do
327
370
  },
328
371
  request_id: 1,
329
372
  )
373
+
374
+ expect(
375
+ described_class.performance_notifier,
376
+ ).to have_received(:notify) do |performance_breakdown|
377
+ expect(performance_breakdown.stash).to eq(request_id: 1)
378
+ end
330
379
  end
331
380
  end
332
381
  end
333
382
 
334
383
  describe ".notify_performance_breakdown_sync" do
335
384
  it "notifies performance breakdown synchronously" do
336
- expect(described_class.performance_notifier).to receive(:notify_sync)
385
+ allow(described_class.performance_notifier).to receive(:notify_sync)
337
386
 
338
387
  described_class.notify_performance_breakdown_sync(
339
388
  {
@@ -345,29 +394,33 @@ RSpec.describe Airbrake do
345
394
  },
346
395
  request_id: 1,
347
396
  )
397
+
398
+ expect(described_class.performance_notifier).to have_received(:notify_sync)
348
399
  end
349
400
  end
350
401
 
351
402
  describe ".notify_queue" do
403
+ before do
404
+ allow(described_class.performance_notifier).to receive(:notify)
405
+ end
406
+
352
407
  context "when :stash key is not provided" do
353
408
  it "doesn't add anything to the stash of the queue" do
354
- expect(described_class.performance_notifier).to receive(:notify) do |queue|
355
- expect(queue.stash).to be_empty
356
- end
357
-
358
409
  described_class.notify_queue(
359
410
  queue: 'bananas',
360
411
  error_count: 10,
361
412
  )
413
+
414
+ expect(
415
+ described_class.performance_notifier,
416
+ ).to have_received(:notify) do |queue|
417
+ expect(queue.stash).to be_empty
418
+ end
362
419
  end
363
420
  end
364
421
 
365
422
  context "when :stash key is provided" do
366
423
  it "adds the value as the stash of the queue" do
367
- expect(described_class.performance_notifier).to receive(:notify) do |queue|
368
- expect(queue.stash).to eq(request_id: 1)
369
- end
370
-
371
424
  described_class.notify_queue(
372
425
  {
373
426
  queue: 'bananas',
@@ -375,13 +428,19 @@ RSpec.describe Airbrake do
375
428
  },
376
429
  request_id: 1,
377
430
  )
431
+
432
+ expect(
433
+ described_class.performance_notifier,
434
+ ).to have_received(:notify) do |queue|
435
+ expect(queue.stash).to eq(request_id: 1)
436
+ end
378
437
  end
379
438
  end
380
439
  end
381
440
 
382
441
  describe ".notify_queue_sync" do
383
442
  it "notifies queue synchronously" do
384
- expect(described_class.performance_notifier).to receive(:notify_sync)
443
+ allow(described_class.performance_notifier).to receive(:notify_sync)
385
444
 
386
445
  described_class.notify_queue_sync(
387
446
  {
@@ -390,6 +449,8 @@ RSpec.describe Airbrake do
390
449
  },
391
450
  request_id: 1,
392
451
  )
452
+
453
+ expect(described_class.performance_notifier).to have_received(:notify_sync)
393
454
  end
394
455
  end
395
456
 
@@ -412,6 +473,7 @@ RSpec.describe Airbrake do
412
473
  end
413
474
  end
414
475
 
476
+ # rubocop:disable RSpec/MessageSpies
415
477
  describe ".close" do
416
478
  after { described_class.reset }
417
479
 
@@ -456,4 +518,5 @@ RSpec.describe Airbrake do
456
518
  end
457
519
  end
458
520
  end
521
+ # rubocop:enable RSpec/MessageSpies
459
522
  end