airbrake-ruby 4.8.0 → 5.2.0

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