airbrake-ruby 4.8.0 → 5.2.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +132 -57
  3. data/lib/airbrake-ruby/async_sender.rb +7 -30
  4. data/lib/airbrake-ruby/backtrace.rb +8 -7
  5. data/lib/airbrake-ruby/benchmark.rb +1 -1
  6. data/lib/airbrake-ruby/code_hunk.rb +1 -1
  7. data/lib/airbrake-ruby/config.rb +59 -15
  8. data/lib/airbrake-ruby/config/processor.rb +71 -0
  9. data/lib/airbrake-ruby/config/validator.rb +9 -3
  10. data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
  11. data/lib/airbrake-ruby/file_cache.rb +1 -1
  12. data/lib/airbrake-ruby/filter_chain.rb +16 -1
  13. data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
  14. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +2 -2
  15. data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
  16. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +5 -5
  17. data/lib/airbrake-ruby/filters/git_repository_filter.rb +3 -0
  18. data/lib/airbrake-ruby/filters/git_revision_filter.rb +2 -0
  19. data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
  20. data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
  21. data/lib/airbrake-ruby/filters/keys_filter.rb +39 -20
  22. data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
  23. data/lib/airbrake-ruby/filters/sql_filter.rb +7 -7
  24. data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
  25. data/lib/airbrake-ruby/filters/thread_filter.rb +5 -4
  26. data/lib/airbrake-ruby/grouppable.rb +12 -0
  27. data/lib/airbrake-ruby/ignorable.rb +1 -0
  28. data/lib/airbrake-ruby/inspectable.rb +2 -2
  29. data/lib/airbrake-ruby/loggable.rb +1 -1
  30. data/lib/airbrake-ruby/mergeable.rb +12 -0
  31. data/lib/airbrake-ruby/monotonic_time.rb +5 -0
  32. data/lib/airbrake-ruby/notice.rb +7 -14
  33. data/lib/airbrake-ruby/notice_notifier.rb +11 -3
  34. data/lib/airbrake-ruby/performance_breakdown.rb +16 -10
  35. data/lib/airbrake-ruby/performance_notifier.rb +80 -58
  36. data/lib/airbrake-ruby/promise.rb +1 -0
  37. data/lib/airbrake-ruby/query.rb +20 -15
  38. data/lib/airbrake-ruby/queue.rb +65 -0
  39. data/lib/airbrake-ruby/remote_settings.rb +105 -0
  40. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  41. data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
  42. data/lib/airbrake-ruby/request.rb +14 -12
  43. data/lib/airbrake-ruby/stat.rb +26 -33
  44. data/lib/airbrake-ruby/sync_sender.rb +3 -2
  45. data/lib/airbrake-ruby/tdigest.rb +43 -58
  46. data/lib/airbrake-ruby/thread_pool.rb +11 -1
  47. data/lib/airbrake-ruby/truncator.rb +10 -4
  48. data/lib/airbrake-ruby/version.rb +11 -1
  49. data/spec/airbrake_spec.rb +206 -71
  50. data/spec/async_sender_spec.rb +3 -12
  51. data/spec/backtrace_spec.rb +44 -44
  52. data/spec/code_hunk_spec.rb +11 -11
  53. data/spec/config/processor_spec.rb +143 -0
  54. data/spec/config/validator_spec.rb +23 -6
  55. data/spec/config_spec.rb +40 -14
  56. data/spec/deploy_notifier_spec.rb +2 -2
  57. data/spec/filter_chain_spec.rb +28 -1
  58. data/spec/filters/dependency_filter_spec.rb +1 -1
  59. data/spec/filters/gem_root_filter_spec.rb +9 -9
  60. data/spec/filters/git_last_checkout_filter_spec.rb +21 -4
  61. data/spec/filters/git_repository_filter.rb +1 -1
  62. data/spec/filters/git_revision_filter_spec.rb +10 -10
  63. data/spec/filters/{keys_whitelist_spec.rb → keys_allowlist_spec.rb} +29 -28
  64. data/spec/filters/{keys_blacklist_spec.rb → keys_blocklist_spec.rb} +39 -29
  65. data/spec/filters/root_directory_filter_spec.rb +9 -9
  66. data/spec/filters/sql_filter_spec.rb +58 -60
  67. data/spec/filters/system_exit_filter_spec.rb +1 -1
  68. data/spec/filters/thread_filter_spec.rb +32 -30
  69. data/spec/fixtures/project_root/code.rb +9 -9
  70. data/spec/loggable_spec.rb +17 -0
  71. data/spec/monotonic_time_spec.rb +11 -0
  72. data/spec/notice_notifier/options_spec.rb +17 -17
  73. data/spec/notice_notifier_spec.rb +20 -20
  74. data/spec/notice_spec.rb +6 -6
  75. data/spec/performance_breakdown_spec.rb +0 -1
  76. data/spec/performance_notifier_spec.rb +220 -73
  77. data/spec/query_spec.rb +1 -1
  78. data/spec/queue_spec.rb +18 -0
  79. data/spec/remote_settings/callback_spec.rb +143 -0
  80. data/spec/remote_settings/settings_data_spec.rb +348 -0
  81. data/spec/remote_settings_spec.rb +187 -0
  82. data/spec/request_spec.rb +1 -3
  83. data/spec/response_spec.rb +8 -8
  84. data/spec/spec_helper.rb +6 -6
  85. data/spec/stat_spec.rb +2 -12
  86. data/spec/sync_sender_spec.rb +14 -12
  87. data/spec/tdigest_spec.rb +7 -7
  88. data/spec/thread_pool_spec.rb +39 -10
  89. data/spec/timed_trace_spec.rb +1 -1
  90. data/spec/truncator_spec.rb +12 -12
  91. metadata +32 -14
@@ -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
@@ -3,7 +3,6 @@ RSpec.describe Airbrake::PerformanceBreakdown do
3
3
  subject do
4
4
  described_class.new(
5
5
  method: 'GET', route: '/', response_type: '', groups: {},
6
- start_time: Time.now
7
6
  )
8
7
  end
9
8
 
@@ -2,18 +2,21 @@ RSpec.describe Airbrake::PerformanceNotifier do
2
2
  let(:routes) { 'https://api.airbrake.io/api/v5/projects/1/routes-stats' }
3
3
  let(:queries) { 'https://api.airbrake.io/api/v5/projects/1/queries-stats' }
4
4
  let(:breakdowns) { 'https://api.airbrake.io/api/v5/projects/1/routes-breakdowns' }
5
+ let(:queues) { 'https://api.airbrake.io/api/v5/projects/1/queues-stats' }
5
6
 
6
7
  before do
7
8
  stub_request(:put, routes).to_return(status: 200, body: '')
8
9
  stub_request(:put, queries).to_return(status: 200, body: '')
9
10
  stub_request(:put, breakdowns).to_return(status: 200, body: '')
11
+ stub_request(:put, queues).to_return(status: 200, body: '')
10
12
 
11
13
  Airbrake::Config.instance = Airbrake::Config.new(
12
14
  project_id: 1,
13
15
  project_key: 'banana',
14
16
  performance_stats: true,
15
17
  performance_stats_flush_period: 0,
16
- query_stats: true
18
+ query_stats: true,
19
+ job_stats: true,
17
20
  )
18
21
  end
19
22
 
@@ -27,9 +30,9 @@ RSpec.describe Airbrake::PerformanceNotifier do
27
30
  func: 'foo',
28
31
  file: 'foo.rb',
29
32
  line: 123,
30
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
31
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
32
- )
33
+ timing: 60000,
34
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
35
+ ),
33
36
  )
34
37
  subject.close
35
38
 
@@ -47,7 +50,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
47
50
  "sum":60000.0,
48
51
  "sumsq":3600000000.0,
49
52
  "tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB"
50
- }\]}\z|x)
53
+ }\]}\z|x),
51
54
  ).to have_been_made
52
55
  end
53
56
 
@@ -57,9 +60,9 @@ RSpec.describe Airbrake::PerformanceNotifier do
57
60
  method: 'POST',
58
61
  route: '/foo',
59
62
  status_code: 200,
60
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
61
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
62
- )
63
+ timing: 60000,
64
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
65
+ ),
63
66
  )
64
67
  subject.close
65
68
 
@@ -74,7 +77,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
74
77
  "sum":60000.0,
75
78
  "sumsq":3600000000.0,
76
79
  "tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB"
77
- }\]}\z|x)
80
+ }\]}\z|x),
78
81
  ).to have_been_made
79
82
  end
80
83
 
@@ -84,10 +87,10 @@ RSpec.describe Airbrake::PerformanceNotifier do
84
87
  method: 'DELETE',
85
88
  route: '/routes-breakdowns',
86
89
  response_type: 'json',
87
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
88
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0),
89
- groups: { db: 131, view: 421 }
90
- )
90
+ timing: 60000,
91
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
92
+ groups: { db: 131, view: 421 },
93
+ ),
91
94
  )
92
95
  subject.close
93
96
 
@@ -116,7 +119,47 @@ RSpec.describe Airbrake::PerformanceNotifier do
116
119
  "tdigest":"AAAAAkA0AAAAAAAAAAAAAUPSgAAB"
117
120
  }
118
121
  }
119
- }\]}\z|x)
122
+ }\]}\z|x),
123
+ ).to have_been_made
124
+ end
125
+
126
+ it "sends full queue" do
127
+ subject.notify(
128
+ Airbrake::Queue.new(
129
+ queue: 'emails',
130
+ error_count: 2,
131
+ groups: { redis: 131, sql: 421 },
132
+ timing: 60000,
133
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
134
+ ),
135
+ )
136
+ subject.close
137
+
138
+ expect(
139
+ a_request(:put, queues).with(body: /
140
+ \A{"queues":\[{
141
+ "queue":"emails",
142
+ "errorCount":2,
143
+ "time":"2018-01-01T00:49:00\+00:00",
144
+ "count":1,
145
+ "sum":60000.0,
146
+ "sumsq":3600000000.0,
147
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB",
148
+ "groups":{
149
+ "redis":{
150
+ "count":1,
151
+ "sum":131.0,
152
+ "sumsq":17161.0,
153
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUMDAAAB"
154
+ },
155
+ "sql":{
156
+ "count":1,
157
+ "sum":421.0,
158
+ "sumsq":177241.0,
159
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUPSgAAB"
160
+ }
161
+ }
162
+ }\]}\z/x),
120
163
  ).to have_been_made
121
164
  end
122
165
 
@@ -126,13 +169,14 @@ RSpec.describe Airbrake::PerformanceNotifier do
126
169
  method: 'GET',
127
170
  route: '/foo',
128
171
  status_code: 200,
129
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
130
- )
172
+ timing: 60000,
173
+ time: Time.new(2018, 1, 1, 0, 0, 20, 0),
174
+ ),
131
175
  )
132
176
  subject.close
133
177
 
134
178
  expect(
135
- a_request(:put, routes).with(body: /"time":"2018-01-01T00:00:00\+00:00"/)
179
+ a_request(:put, routes).with(body: /"time":"2018-01-01T00:00:00\+00:00"/),
136
180
  ).to have_been_made
137
181
  end
138
182
 
@@ -142,21 +186,21 @@ RSpec.describe Airbrake::PerformanceNotifier do
142
186
  method: 'GET',
143
187
  route: '/foo',
144
188
  status_code: 200,
145
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0)
146
- )
189
+ timing: 213,
190
+ ),
147
191
  )
148
192
  subject.notify(
149
193
  Airbrake::Request.new(
150
194
  method: 'GET',
151
195
  route: '/foo',
152
196
  status_code: 200,
153
- start_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
154
- )
197
+ timing: 123,
198
+ ),
155
199
  )
156
200
  subject.close
157
201
 
158
202
  expect(
159
- a_request(:put, routes).with(body: /"count":2/)
203
+ a_request(:put, routes).with(body: /"count":2/),
160
204
  ).to have_been_made
161
205
  end
162
206
 
@@ -166,18 +210,18 @@ RSpec.describe Airbrake::PerformanceNotifier do
166
210
  method: 'GET',
167
211
  route: '/foo',
168
212
  status_code: 200,
169
- start_time: Time.new(2018, 1, 1, 0, 0, 49, 0),
170
- end_time: Time.new(2018, 1, 1, 0, 0, 50, 0)
171
- )
213
+ timing: 1000,
214
+ time: Time.new(2018, 1, 1, 0, 0, 49, 0),
215
+ ),
172
216
  )
173
217
  subject.notify(
174
218
  Airbrake::Request.new(
175
219
  method: 'GET',
176
220
  route: '/foo',
177
221
  status_code: 200,
178
- start_time: Time.new(2018, 1, 1, 0, 1, 49, 0),
179
- end_time: Time.new(2018, 1, 1, 0, 1, 55, 0)
180
- )
222
+ timing: 6000,
223
+ time: Time.new(2018, 1, 1, 0, 1, 49, 0),
224
+ ),
181
225
  )
182
226
  subject.close
183
227
 
@@ -191,8 +235,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
191
235
  {"method":"GET","route":"/foo","statusCode":200,
192
236
  "time":"2018-01-01T00:01:00\+00:00","count":1,"sum":6000.0,
193
237
  "sumsq":36000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUW7gAAB"}\]}
194
- \z|x
195
- )
238
+ \z|x,
239
+ ),
196
240
  ).to have_been_made
197
241
  end
198
242
 
@@ -202,18 +246,18 @@ RSpec.describe Airbrake::PerformanceNotifier do
202
246
  method: 'GET',
203
247
  route: '/foo',
204
248
  status_code: 200,
205
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
206
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
207
- )
249
+ timing: 60000,
250
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
251
+ ),
208
252
  )
209
253
  subject.notify(
210
254
  Airbrake::Request.new(
211
255
  method: 'POST',
212
256
  route: '/foo',
213
257
  status_code: 200,
214
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0),
215
- end_time: Time.new(2018, 1, 1, 0, 50, 0, 0)
216
- )
258
+ timing: 60000,
259
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
260
+ ),
217
261
  )
218
262
  subject.close
219
263
 
@@ -227,8 +271,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
227
271
  {"method":"POST","route":"/foo","statusCode":200,
228
272
  "time":"2018-01-01T00:49:00\+00:00","count":1,"sum":60000.0,
229
273
  "sumsq":3600000000.0,"tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAB"}\]}
230
- \z|x
231
- )
274
+ \z|x,
275
+ ),
232
276
  ).to have_been_made
233
277
  end
234
278
 
@@ -238,20 +282,20 @@ RSpec.describe Airbrake::PerformanceNotifier do
238
282
  method: 'DELETE',
239
283
  route: '/routes-breakdowns',
240
284
  response_type: 'json',
241
- start_time: Time.new(2018, 1, 1, 0, 0, 20, 0),
242
- end_time: Time.new(2018, 1, 1, 0, 0, 22, 0),
243
- groups: { db: 131, view: 421 }
244
- )
285
+ timing: 2000,
286
+ time: Time.new(2018, 1, 1, 0, 0, 20, 0),
287
+ groups: { db: 131, view: 421 },
288
+ ),
245
289
  )
246
290
  subject.notify(
247
291
  Airbrake::PerformanceBreakdown.new(
248
292
  method: 'DELETE',
249
293
  route: '/routes-breakdowns',
250
294
  response_type: 'json',
251
- start_time: Time.new(2018, 1, 1, 0, 0, 30, 0),
252
- end_time: Time.new(2018, 1, 1, 0, 0, 32, 0),
253
- groups: { db: 55, view: 11 }
254
- )
295
+ timing: 2000,
296
+ time: Time.new(2018, 1, 1, 0, 0, 30, 0),
297
+ groups: { db: 55, view: 11 },
298
+ ),
255
299
  )
256
300
  subject.close
257
301
 
@@ -280,7 +324,56 @@ RSpec.describe Airbrake::PerformanceNotifier do
280
324
  "tdigest":"AAAAAkA0AAAAAAAAAAAAAkEwAABDzQAAAQE="
281
325
  }
282
326
  }
283
- }\]}\z|x)
327
+ }\]}\z|x),
328
+ ).to have_been_made
329
+ end
330
+
331
+ it "groups queues by queue key" do
332
+ subject.notify(
333
+ Airbrake::Queue.new(
334
+ queue: 'emails',
335
+ error_count: 2,
336
+ groups: { redis: 131, sql: 421 },
337
+ timing: 60000,
338
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
339
+ ),
340
+ )
341
+ subject.notify(
342
+ Airbrake::Queue.new(
343
+ queue: 'emails',
344
+ error_count: 3,
345
+ groups: { redis: 131, sql: 421 },
346
+ timing: 60000,
347
+ time: Time.new(2018, 1, 1, 0, 49, 0, 0),
348
+ ),
349
+ )
350
+ subject.close
351
+
352
+ expect(
353
+ a_request(:put, queues).with(body: /
354
+ \A{"queues":\[{
355
+ "queue":"emails",
356
+ "errorCount":5,
357
+ "time":"2018-01-01T00:49:00\+00:00",
358
+ "count":2,
359
+ "sum":120000.0,
360
+ "sumsq":7200000000.0,
361
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUdqYAAC",
362
+ "groups":{
363
+ "redis":{
364
+ "count":2,
365
+ "sum":262.0,
366
+ "sumsq":34322.0,
367
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUMDAAAC"
368
+ },
369
+ "sql":{
370
+ "count":2,
371
+ "sum":842.0,
372
+ "sumsq":354482.0,
373
+ "tdigest":"AAAAAkA0AAAAAAAAAAAAAUPSgAAC"
374
+ }
375
+ }
376
+ }\]}\z/x),
284
377
  ).to have_been_made
285
378
  end
286
379
 
@@ -290,18 +383,18 @@ RSpec.describe Airbrake::PerformanceNotifier do
290
383
  method: 'GET',
291
384
  route: '/foo',
292
385
  status_code: 200,
293
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
294
- )
386
+ timing: 123,
387
+ ),
295
388
  )
296
389
  subject.close
297
390
 
298
391
  expect(promise).to be_an(Airbrake::Promise)
299
- expect(promise.value).to eq('' => nil)
392
+ expect(promise.value).to eq('' => '')
300
393
  end
301
394
 
302
395
  it "checks performance stat configuration" do
303
396
  request = Airbrake::Request.new(
304
- method: 'GET', route: '/foo', status_code: 200, start_time: Time.new
397
+ method: 'GET', route: '/foo', status_code: 200, timing: 123,
305
398
  )
306
399
  expect(Airbrake::Config.instance).to receive(:check_performance_options)
307
400
  .with(request).and_return(Airbrake::Promise.new)
@@ -317,15 +410,15 @@ RSpec.describe Airbrake::PerformanceNotifier do
317
410
  method: 'POST',
318
411
  route: '/foo',
319
412
  status_code: 200,
320
- start_time: Time.new
321
- )
413
+ timing: 123,
414
+ ),
322
415
  )
323
416
  subject.close
324
417
 
325
418
  expect(
326
419
  a_request(:put, routes).with(
327
- body: /\A{"routes":\[.+\],"environment":"test"}\z/x
328
- )
420
+ body: /\A{"routes":\[.+\],"environment":"test"}\z/x,
421
+ ),
329
422
  ).to have_been_made
330
423
  end
331
424
 
@@ -346,7 +439,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
346
439
  project_id: 1,
347
440
  project_key: 'banana',
348
441
  performance_stats: true,
349
- performance_stats_flush_period: flush_period
442
+ performance_stats_flush_period: flush_period,
350
443
  )
351
444
 
352
445
  subject.notify(
@@ -354,8 +447,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
354
447
  method: 'GET',
355
448
  route: '/foo',
356
449
  status_code: 200,
357
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
358
- )
450
+ timing: 123,
451
+ ),
359
452
  )
360
453
 
361
454
  subject.notify(
@@ -363,8 +456,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
363
456
  method: 'POST',
364
457
  route: '/foo',
365
458
  query: 'SELECT * FROM things',
366
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
367
- )
459
+ timing: 123,
460
+ ),
368
461
  )
369
462
 
370
463
  sleep(flush_period + 0.5)
@@ -383,8 +476,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
383
476
  method: 'GET',
384
477
  route: '/foo',
385
478
  status_code: 200,
386
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
387
- )
479
+ timing: 1,
480
+ ),
388
481
  )
389
482
  subject.close
390
483
 
@@ -397,13 +490,29 @@ RSpec.describe Airbrake::PerformanceNotifier do
397
490
  method: 'POST',
398
491
  route: '/foo',
399
492
  query: 'SELECT * FROM things',
400
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
401
- )
493
+ timing: 1,
494
+ ),
402
495
  )
403
496
  subject.close
404
497
 
405
498
  expect(a_request(:put, queries)).not_to have_been_made
406
499
  end
500
+
501
+ it "returns a rejected promise" do
502
+ promise = subject.notify(
503
+ Airbrake::Query.new(
504
+ method: 'POST',
505
+ route: '/foo',
506
+ query: 'SELECT * FROM things',
507
+ timing: 1,
508
+ ),
509
+ )
510
+ subject.close
511
+
512
+ expect(promise.value).to eq(
513
+ 'error' => 'Airbrake::Query was ignored by a filter',
514
+ )
515
+ end
407
516
  end
408
517
 
409
518
  context "when a filter that modifies payload was defined" do
@@ -419,18 +528,56 @@ RSpec.describe Airbrake::PerformanceNotifier do
419
528
  method: 'POST',
420
529
  route: '/foo',
421
530
  query: 'SELECT * FROM things',
422
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
423
- )
531
+ timing: 123,
532
+ ),
424
533
  )
425
534
  subject.close
426
535
 
427
536
  expect(
428
537
  a_request(:put, queries).with(
429
- body: /\A{"queries":\[{"method":"POST","route":"\[Filtered\]"/
430
- )
538
+ body: /\A{"queries":\[{"method":"POST","route":"\[Filtered\]"/,
539
+ ),
431
540
  ).to have_been_made
432
541
  end
433
542
  end
543
+
544
+ context "when provided :timing is zero" do
545
+ it "doesn't notify" do
546
+ queue = Airbrake::Queue.new(queue: 'bananas', error_count: 0, timing: 0)
547
+ subject.notify(queue)
548
+ subject.close
549
+
550
+ expect(a_request(:put, queues)).not_to have_been_made
551
+ end
552
+
553
+ it "returns a rejected promise" do
554
+ queue = Airbrake::Queue.new(queue: 'bananas', error_count: 0, timing: 0)
555
+ promise = subject.notify(queue)
556
+ subject.close
557
+
558
+ expect(promise.value).to eq('error' => ':timing cannot be zero')
559
+ end
560
+ end
561
+ end
562
+
563
+ describe "#notify_sync" do
564
+ it "notifies synchronously" do
565
+ retval = subject.notify_sync(
566
+ Airbrake::Query.new(
567
+ method: 'POST',
568
+ route: '/foo',
569
+ query: 'SELECT * FROM things',
570
+ timing: 123,
571
+ ),
572
+ )
573
+
574
+ expect(
575
+ a_request(:put, queries).with(
576
+ body: %r|\A{"queries":\[{"method":"POST","route":"/foo"|,
577
+ ),
578
+ ).to have_been_made
579
+ expect(retval).to eq('' => '')
580
+ end
434
581
  end
435
582
 
436
583
  describe "#close" do
@@ -449,8 +596,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
449
596
  method: 'POST',
450
597
  route: '/foo',
451
598
  query: 'SELECT * FROM things',
452
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
453
- )
599
+ timing: 123,
600
+ ),
454
601
  )
455
602
  subject.close
456
603
  end
@@ -458,7 +605,7 @@ RSpec.describe Airbrake::PerformanceNotifier do
458
605
  it "logs the exit message" do
459
606
  allow(Airbrake::Loggable.instance).to receive(:debug)
460
607
  expect(Airbrake::Loggable.instance).to receive(:debug).with(
461
- /performance notifier closed/
608
+ /performance notifier closed/,
462
609
  )
463
610
  subject.close
464
611
  end
@@ -480,8 +627,8 @@ RSpec.describe Airbrake::PerformanceNotifier do
480
627
  method: 'POST',
481
628
  route: '/foo',
482
629
  status_code: 200,
483
- start_time: Time.new(2018, 1, 1, 0, 49, 0, 0)
484
- )
630
+ timing: 123,
631
+ ),
485
632
  )
486
633
  subject.close
487
634